Redux简介
Redux是一个集中存储和管理全局状态的库,通过reducer纯函数来定义怎样更新state,然后通过dispatch action更新state,state每次更新都要返回一个新对象,也就是说state是不可变的。
基于reducer纯函数和不可变state,redux应用可以实现时间旅行式的调试;
特点:
- 单一数据源store;
- 纯函数reducer;
- 不可变state;
标准(传统、Legacy)Redux
1 | // 1.1 定义action |
异步Action解决方案:redux-thunk,redux-promise
1 | // redux-thunk |
1 | // redux-promise |
简化react组件订阅redux store的过程 —— react-redux
Hooks:
- useSelector,构建redux state选择器,并订阅redux state的更新
- useDispatch,获取dispatch函数,用于分发action
- useStore,获取redux store实例
Components:
- Provider,其实就是react内置组件Context.Provider
- connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?),是一个HOC组件,用于向react组件内注入redux state和dispatch函数,使组件订阅redux state的更新
- mapStateToProps(state, ownProps?),用于将redux state注入组件的props中,并使组件订阅redux state的更新,可以访问到ownProps(具体含义见下文细节)
- mapDispatchToProps
- mapDispatchToProps(dispatch, ownProps?)用于将dispatch封装为各种action的派发函数,并注入connected component,同样可以访问到ownProps
- mapDispatchToPropsObj,作用相同,但是一个action creators构成的对象,这个对象会传递给bindActionCreators,将结果注入connected component,该形式更为简便,redux推荐使用该形式注入action派发函数
- mergeProps(stateProps,dispatchProps,ownProps)用于合并stateProps、dispatchProps和ownProps,默认返回
{ ...ownProps, ...stateProps, ...dispatchProps }
- options
- context,只有v6可用,用户可提供自定义的context
- areStatesEqual,默认为严格比较(===),决定是否重新执行mapStateToProps;
- areOwnPropsEqual,默认为浅比较,决定ownProps前后是否一致
- areStatePropsEqual,默认为浅比较,决定stateProps前后是否一致
- areMergedPropsEqual,默认为浅比较,决定mergeProps前后是否一致
- forwardRef,只有v6可用,设为true,则connect执行后得到的HOC将ref转发到connected components
Utils:
- bindActionCreators(),第一个参数为action creator或action creators构成的对象,第二个参数为dispatch,对于单个action creator会返回一个绑定dispatch后的匿名函数,对于action creators对象会返回一个具有同样key的对象,其value是绑定dispatch后的函数;
- batch(),本质是react的unstable_batchedUpdates,将多次dispatch合并进一次组件渲染中,react18默认启用batched updates特性,所以不必使用该api;
性能优化:
- 通过selector缓存数据提取函数;
- mapStateToProps应当是纯函数,应该是同步执行的,尽量避免耗时操作或只在输入改变时执行耗时操作,只在必要时返回一个新的引用;
细节:
- ownProps即传递给connected component的props;
- 对于mapStateToProps,state或ownProps发生改变会导致mapStateToProps的重新调用;
- connect实现了一个浅比较的shouldComponentUpdate,当stateProps或ownProps的引用改变或字段改变,会触发重渲染;
- 若mapStateToProps未定义,则connected component不会订阅redux state的更新;
- 若mapDispatchToProps未定义,connected component的props会接收到dispatch;若定义了,则不会传入dispatch;
重点:
现代化的react-redux不推荐通过connect集成react与redux store,取而代之的是直接在函数组件中使用useSelector、useDispatch
原理:
- 数据传递
Provider在顶层提供一个Context.Provider,并将store以context value形式提供给下层组件,connect从context中取到store,并对mapStateToProps、mapDispatchToProps、mergeProps进行一系列计算,将计算得到的props注入被connect的组件
- 组件更新
7.0版本是通过connect执行后得到HOC,HOC内订阅store更新,并通过useReducer更新子组件;
8.0版本更新组件的方式改为使用useSyncExternalStore,通过redux store的subscribe订阅store的更新,dispatch action之后store发生变化,执行react通过subscribe注册进来的listener,然后react触发一次同步更新(其实之后在render和commit阶段还会进行store一致性检查,一旦此时store改变,就再触发一次同步更新)
现代Redux —— Redux Toolkit(RTK)
API:
- configureStore,创建、初始化store,内置了redux-thunk等middleware
- createSlice,定义局部的reducer,自动生成action creator
- createAsyncThunk,创建thunk action creator
1 | // store.js |
1 | // userSlice.js |
1 | // Login.jsx |
1 | // UserInfo.jsx |
1 | // App.jsx |