官网:https://redux.js.org/
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。具有以下特点(以下内容根据官网内容翻译):
- 可预测的
Redux 可帮助您编写行为一致、在不同环境(客户端、服务器和本机)中运行且易于测试的应用程序。- 集中管理
将应用程序中的状态和逻辑集中管理,以实现强大的功能,如撤消/重做、状态持久性等。- 可调试
借助于Redux DevTools工具,可以轻松的追踪应用状态变更的时间、位置、原因以及方式。Redux的架构允许您记录更改,使用“time-travel debugging”,甚至将完整的错误报告发送到服务器。- 灵活性
Redux 适用于任何 UI 层,并具有庞大的插件生态系统来满足您的需求。
以下内容将详细讲解React
项目如果集成Redux
。
通过以下命令安装redux
、react-redux
、@reduxjs/toolkit
npm install redux --save
# React 绑定库
npm install react-redux --save
npm install @reduxjs/toolkit --save
#开发者工具
npm install --save-dev redux-devtools
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
我们可以在项目src
目录下创建src/reducers/nodes.ts
的文件,该文件用来管理node相关状态信息,当然也可以创建其他的文件来管理其他状态=。原则上一个reducer管理一种类型的状态,如创建todo.ts
管理todo相关信息。
// nodes.ts
type ActionType = 'ADD_NODE' | 'DEL_NODE';
interface Action {
type: ActionType;
value: any;
}
const nodes = (state = [], action: Action) => {
switch (action.type) {
case 'ADD_NODE': {
// 往数组最后添加value
return [...state, action.value];
}
case 'DEL_NODE': {
// 过滤掉元素,达到删除的效果
return state.filter(item => item !== action.value);
}
}
return state;
}
export default nodes;
我们需要把多个不同 reducer 函数,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。
创建src/reducers/index.ts
文件,用于整合src/reducers
目录下的多个reducer。
// src/reducers/index.ts
import { combineReducers } from 'redux';
import nodes from './nodes';
// 可以引入其他reducer
const reducers = combineReducers({
nodes,
// 可以添加其他reducer
});
创建一个 Redux store 来以存放应用中所有的 state。
注意:老版本的redux
通过createStore
方法创建store,新版本(指的是4.2+)则将该方法标记为废弃@deprecated,并建议通过configureStore
来创建store。src/reducers/index.ts
完整的代码如下:
// src/reducers/index.ts
import {combineReducers, createStore} from 'redux';
import { configureStore } from '@reduxjs/toolkit';
import nodes from './nodes';
// 可以引入其他reducer
const reducers = combineReducers({
nodes,
// 可以添加其他reducer
});
export const store = configureStore({reducer: reducers});
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说通过 store.dispatch()
方法将 action 传到 store。
// src/sctions/index.ts
export const addNode = node => ({
type: 'ADD_NODE',
value: node
});
export const delNode = node => ({
type: 'DEL_NODE',
value: node
});
在具体业务逻辑代码中,通过调用store.dispatch(action)
方法来分发 action,这是触发 state 变化的惟一途径。
store.dispatch(action)
会使用当前 getState() 的结果和传入的 action 以同步方式的调用 store 的 reduce 函数。返回值会被作为下一个 state,同时变化监听器(change listener)会被触发。例:
import {store} from '../reducers'; // 引用store
// 业务代码...
store.dispatch(addNode(model.id));
// 业务代码...
connect()
属于React中的高阶组件,作用是连接 React 组件与 Redux store,使得React组件能过访问到Redux store。
// src/index.ts
import {store} from './reducers';
// ...
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
// 根节点需要被包裹
<Provider store={store}>
<MyRootComponent />
</Provider>
);
业务组件:
// src/components/my-component.ts
import {Dispatch} from 'redux';
import {connect} from 'react-redux';
import {store} from '../reducers';
interface IMyComponentProps{
nodes: string[];
addNode: (value: string| null) => void;
}
interface IMyComponentState{
}
class MyComponentextends React.Component<IMyComponentProps, IMyComponentState> {
// 省去MyComponent组件部分代码
method(node: string) {
// 调用props中的addNode
this.props.addNode(node);
}
render() {
return (
// 访问redux中的nodes
<div>{this.props.nodes.length}</div>
)
}
}
interface IStoreState {
nodes: string[];
}
const mapStateToProps = (state: IStoreState, ownerProps: IMyComponentProps): { nodes: string[] } => ({
nodes: state.nodes
});
const mapDispatchToProps = (dispatch: Dispatch, ownProps: IMyComponentProps): {
addNode: (value: string | null) => void,
delNode: (value: string | null) => void,
} => ({
addNode: (value: string | null) => dispatch({type: 'ADD_NODE', value}),
delNode: (value: string | null) => dispatch({type: 'DEL_NODE', value}),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
方法connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
的主要作用是连接 React 组件与 Redux store。 连接操作不会改变原来的组件类。 反而返回一个新的已与 Redux store 连接的组件类。
connect()
参数如下:
[mapStateToProps(state, [ownProps]): stateProps]
(Function): 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps
函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store。如果指定了该回调函数中的第二个参数 ownProps
,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps
也会被调用(例如,当 props 接收到来自父组件一个小小的改动,那么你所使用的 ownProps 参数,mapStateToProps
都会被重新计算)。
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps]
(Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将action creator的返回值作为参数执行。这些属性会被合并到组件的 props 中。
dispatch
函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch
函数与 action creator 以某种方式绑定在一起。[mergeProps(stateProps, dispatchProps, ownProps): props]
(Function): 如果指定了这个参数,mapStateToProps()
与 mapDispatchToProps()
的执行结果和组件自身的 props
将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps)
的结果。
[options]
(Object) 如果指定这个参数,可以定制 connector 的行为。
[pure = true]
(Boolean): 如果为 true
,connector 将执行 shouldComponentUpdate
并且浅对比 mergeProps
的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true
。[withRef = false]
(Boolean): 如果为 true
,connector 会保存一个对被包装组件实例的引用,该引用通过 getWrappedInstance()
方法获得。默认值为 false
。至此React项目如何集成Redux讲解完毕,如有疑问,欢迎私信或者评论区交流。
也希望各位能够点个赞或者收藏⭐
:)
扩展阅读:
React + Antd实现动态切换主题功能
React + Antd实现动态切换主题功能之二(默认主题与暗黑色主题切换)
React + Router + Antd实现多标签页功能(具体代码实现)