如何在 React 中设置 Redux(2020)
当前计数:{count}
Redux 可能是迄今为止的React全局状态管理库。它消除了prop-drilling的问题,让我们能够以可扩展的方式管理应用程序状态。
介绍得已经足够了,现在让我们在 React 项目中进行设置!
注意:本文假设您了解 redux 的基础知识。如果没有,请在继续阅读之前先阅读redux 文档。
这个博客的目标是什么?
理解并使用 redux 和CRA设置经典的反例。
最后还有奖励部分等着您!
您可以从这里克隆此博客的最终结果。
步骤 1: 设置你的 React 项目
您可以自行设置一个 React 项目并配置babel、webpack ,或者您可以使用create-react-app来启动一个 React 项目,这正是我们现在要做的。
$ npx create-react-app my-react-redux-app
在终端/命令提示符中输入上述命令。在此之前,请确保您的计算机上安装了最新版本的Node 。
这里,my-react-redux-app 是项目文件夹的名称。
$ cd my-react-redux-app
$ npm start
现在将目录(cd)更改为 my-react-redux-app,然后在终端/命令提示符中输入以启动(npm start)服务器。
瞧! React 项目现已设置完毕。您应该能够在浏览器中看到类似以下内容的屏幕:
第 2 步:安装 redux 和 react-redux
npm install redux react-redux
或者
yarn add redux react-redux
现在我们已经安装了软件包,我们可以继续进行设置。
react-redux让我们可以轻松地将 redux 与我们的 react 应用程序连接起来。
步骤 3:在 index.js 中设置 Redux Store
在此步骤中,我们将修改React 项目层次结构中最顶层的组件,即所有组件的父级。务必在最顶层组件上执行此步骤,因为这可确保 Redux Store 可供所有组件使用。
我们的index.js看起来像:
--------------------------- index.js ---------------------------
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
// REDUX
import { Provider } from 'react-redux';
import store from './redux/store';
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root'),
);
在这里,我们从react-redux导入了名为“ Provider ”的东西。
Provider是react-redux库提供的一个组件。它封装了我们的组件。如你所见,它还接收一个名为 store 的 prop (也就是我们的 redux store)。
在继续之前,为了保持项目结构的条理性,我们将在 src 文件夹中创建一个名为redux的文件夹,所有与 redux 相关的代码/逻辑都将放在这个文件夹中。这样,我们的项目在需要时就更易于阅读、测试和扩展。
现在让我们创建我们的商店。
在 ./src/redux 目录中创建一个名为store.js的文件。(路径 - ./src/redux/store.js)
------------------------- ./src/redux/store.js ---------------------
import { createStore } from 'redux';
import rootReducer from './rootReducer';
const store = createStore(rootReducer);
export default store;
这里,我们使用redux 的createStore()函数来创建一个 store!(好吧,这个解释有点多余😜,因为名字本身就一目了然)。我们可以看到,我们还导入了一个名为rootReducer 的文件,但我们还没有创建它,所以现在就来创建它吧。
在与商店相同的目录中创建一个名为rootReducer的文件(即路径 - ./src/redux/rootReducer.js)
--------------------- ./src/redux/rootReducer.js -------------------
import { combineReducers } from 'redux';
import counterReducer from './Counter/counter.reducer';
const rootReducer = combineReducers({
counter: counterReducer,
});
export default rootReducer;
这里,combineReducers()顾名思义,将多个 Reducer 合并为一个 Reducer。在 Redux 中,我们可以根据需要创建任意数量的 Reducer。理想情况下,为每个不依赖于任何其他 Action 的操作创建一个新的 Reducer。由于store.js中的createStore()只能接受一个 Reducer,因此使用combineReducer()将多个 Reducer 合并为一个。
这样,我们就成功创建了rootReducer,但可以看到我们导入了一个名为counterReducer的文件,而我们还没有创建它😗。我知道这有点繁琐,但相信我,坚持住!你只需要在设置 redux 时执行一次即可。设置完成后,接下来的体验会非常流畅。
counterReducer是我们一开始提到的反例的 Reducer 函数。从下一步开始,我们将开始实现我们的反例。
步骤 4:设置计数器 reducer/actions/types
首先,让我们在 redux 文件夹中创建一个名为Counter的文件夹(路径 - ./src/redux/Counter)。
在 Counter 文件夹中,我们创建 3 个文件 -
-
counter.types.js
-
counter.actions.js
-
counter.reducer.js
文件名的含义非常明显。(如果您对此有任何疑问,请在下面的评论部分告诉我)
我们先来创建计数器的类型。我们需要两种类型,一种用于增加计数器,另一种用于减少计数器。
--------------- ./src/redux/Counter/counter.types.js ---------------
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
在这里,我们导出这两个常量,以便它们可以被导入到其他文件中。
接下来,让我们为计数器创建动作。
--------------- ./src/redux/Counter/counter.actions.js -------------
import { INCREMENT, DECREMENT } from './counter.types';
export const increaseCounter = () => {
return {
type: INCREMENT,
};
};
export const decreaseCounter = () => {
return {
type: DECREMENT,
};
};
在这里,我们从counter.types.js文件导入我们的类型,并将它们作为类型传递到各自的操作中。
现在,让我们为反例创建减速器。
------------------ ./src/redux/counter.reducer.js ------------------
import { INCREMENT, DECREMENT } from './counter.types';
const INITIAL_STATE = {
count: 0,
};
const reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case INCREMENT:
return {
...state, count: state.count + 1,
};
case DECREMENT:
return {
...state, count: state.count - 1,
};
default: return state;
}
};
export default reducer;
首先,我们在顶部导入类型。然后声明一个名为INITIAL_STATE的常量,它将作为此特定 Reducer 的默认状态。之后,我们创建一个名为Reducer的函数,它接受两个参数——state 和 action。State 的初始值为 INITIAL_STATE,action 接收来自 action creator 从counter.actions.js文件传递的任何数据(有效负载)。
在 Reducer 函数内部,我们使用JavaScript 中的switch-case 语句,并在每个 case 语句中返回更新后的状态。我们使用扩展运算符 (…)将状态复制到新对象中,然后在该状态中添加我们想要更改的内容。
⚠️ 永远记住:我们永远不会改变原始状态!每次我们需要进行更改时,我们都会返回一个新的状态对象。
最后,我们导出我们的 reducer,然后将其导入到 _rootReducer.js 文件中。
这样,我们的计数器 Reducer 就准备好了!从下一步开始,我们将编写一些 JSX 代码,以便在 Web 应用上显示增量和减量按钮。
步骤 5:JSX 用于增加/减少按钮
为了演示如何在 Web 应用中使用 Redux,我们需要在 Web 应用上展示一些内容。因此,我们将编写一些基本的 JSX 代码,然后将其连接到 Redux Store。
让我们打开App.js文件(路径 - ./src/app.js)
将 App.js 中现有的样板代码替换为以下内容
-------------------------- ./src/App.js ----------------------------
import React from 'react';
import './App.css';
function App() {
return (
<div className='App'>
<div>Count: 0</div>
<button>Increase Count</button>
<button>Decrease Count</button>
</div>
);
}
export default App;
这里,我们刚刚添加了两个目前不执行任何操作的按钮,并显示一个静态计数值。
现在,让我们在下一步中将 redux 状态和动作连接到这个组件。
步骤 6:将 redux state/actions 连接到组件
现在一切都已设置完毕,最后一步是在我们的组件中使用 redux 状态和操作。
import React from "react"
import "./App.css"
import { connect } from "react-redux"
import {
increaseCounter,
decreaseCounter,
} from "./redux/Counter/counter.actions"
function App(props) {
return (
<div className="App">
<div>Count: {props.count}</div>
<button onClick={() => props.increaseCounter()}>Increase Count</button>
<button onClick={() => props.decreaseCounter()}>Decrease Count</button>
</div>
)
}
const mapStateToProps = state => {
return {
count: state.counter.count,
}
}
const mapDispatchToProps = dispatch => {
return {
increaseCounter: () => dispatch(increaseCounter()),
decreaseCounter: () => dispatch(decreaseCounter()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
在这里,我们从react-redux库导入connect函数,我们还导入了increaseCounter和decreaseCounter动作。
connect 函数是一个高阶组件(HOC),它本质上是一个组件,并向其添加一些 props,然后返回添加了新 props 的组件。查看导出组件的 App.js 文件的最后一行,我们可以看到这里使用了 connect,如下所示:
export default connect(mapStateToProps, mapDispatchToProps)(App)
connect 接受两个函数作为参数,即mapStateToProps和mapDispatchToProps。
现在让我们看看这两个函数的作用,
const mapStateToProps = state => {
return {
count: state.counter.count,
}
}
const mapDispatchToProps = dispatch => {
return {
increaseCounter: () => dispatch(increaseCounter()),
decreaseCounter: () => dispatch(decreaseCounter()),
}
}
mapStateToProps函数顾名思义,它将 Redux 状态映射到其所在组件的 props 中。因此,它基本上会将你从该函数返回的任何状态添加到你的组件中。在我们的计数器示例中,我从 Redux 状态返回了count,因此现在我可以从 App 组件内的 props 中访问 count。
mapDispatchToProps函数的功能非常类似,但它不是将状态添加到 props,而是将我们的操作添加到 props!从此函数返回的任何操作都会添加到我们的组件中。正如您所见,在我们的示例中,我返回了两个操作,即increaseCounter和decreaseCounter,因此我们可以从 props 中访问它们,然后在相应的按钮点击时释放它们。
现在,我们有一个功能齐全的 React-redux 应用!如果您喜欢这篇博客或有任何疑问,请在评论区留言!
额外奖励:将 redux-dev-tools 添加到项目中
首先,从这里下载Chrome 浏览器 Redux 扩展
其次,使用以下命令将 redux dev tools 包从 npm 安装到你的项目中,
npm install --save redux-devtools-extension
第三,更新您的store.js以使用composeWithDevtools,如下所示,
------------------------- ./src/redux/store.js ---------------------
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from './rootReducer';
const store = createStore(
rootReducer,
composeWithDevTools(),
);
export default store;
就这样!现在你可以访问 Chrome Dev Tools 来使用 Redux 了!
redux 的 chrome dev tools 看起来像这样:
您可以从这里克隆此博客的最终结果。
感谢您阅读这篇文章!希望它能给您带来一些价值😊。
您可以关注我的推特,以便在我发布新文章时第一时间收到更新,或者直接在推特上分享您的想法!再见!