Redux和React-Redux学习笔记

Redux 作为一个全局的状态管理工具,并不只能在 React 中进行使用,也可将其应用在其他框架甚至是 jQuery 中。

本文记录一下 Redux 学习中比较晦涩的部分,用以加深印象。

纯 Redux

redux 文件夹基本组成

  • store.js
1
2
3
4
5
6
7
import { legacy_createStore as createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import countReducer from "./count.reducer";

const store = createStore(countReducer, applyMiddleware(thunk));

export default store;

备注:

  1. redux-thunk 是一个中间件,用于异步 action 获取 dispatch 方法
  2. createStore 方法已经不推荐使用
  • action.js
1
2
3
4
5
6
7
8
import { PLUS, SUBTRACT } from "./constant";

export const createPlusAction = (data) => ({ type: PLUS, data });
export const createSubtractAction = (data) => ({ type: SUBTRACT, data });

// 异步 action redux-thunk 中间件
export const createPlusAsyncAction = (data, timeout) => (dispatch) =>
setTimeout(() => dispatch(createPlusAction(data)), timeout);

备注:同步 action 需返回一个对象,用于传递给 reducer,方便代码复用。

  • reducer.js
1
2
3
4
5
6
import { PLUS, SUBTRACT } from "./constant";

const countReducer = (prevState = 0, { type, data }) =>
(prevState += (type === PLUS && data) || (type === SUBTRACT && -data));

export default countReducer;

备注:reducer 是纯函数,基本不会处理数据操作之外的业务逻辑。

  • constant.js
1
2
export const PLUS = "plus";
export const SUBTRACT = "subtract";

备注:字面量常量集,方便复用,提升代码的健壮性。

redux store 监听

1
2
3
4
5
6
// 组件中
useEffect(() => {
store.subscribe(() => {
setCount(store.getState());
});
}, []);

Redux 默认无法在 React 组件中进行对数据监听,这会导致视图层不会重新渲染。需在生命周期钩子中对其进行订阅。

也可在入口文件中对入口的 render 方法进行订阅,从而一劳永逸(不过可能会在每次数据更新时可能由于 diffing 算法造成不必要的性能开销)。


react-redux

react-redux 是由 Redux 官方维护的一套专供与 React 技术栈的 Redux 封装库。

React-Redux 将 UI 和 数据完全分离开来,分为 UI 组件和容器组件。UI 组件中不会进行任何有关 redux 状态管理的操作,所有 redux 相关操作都提升到容器组件中来进行。

connect 高阶组件

connect 方法的 api:
connect(mapStateToProps, mapDispatchToProps)(UI)

  • mapStateToProps:需传递一个回调函数,用于给 UI 组件传递 redux 中的 state。
  • mapDispatchToProps:同上,用于给 UI 组件 redux 中操作 state 的方法(dispatch)。
1
2
3
4
5
6
7
8
9
export default connect(
(state) => ({ count: state }),
(dispatch) => ({
plus: (number) => dispatch(createPlusAction(number)),
subtract: (number) => dispatch(createSubtractAction(number)),
plusAsync: (number, timeout) =>
dispatch(createPlusAsyncAction(number, timeout)),
})
)(CountUI);

省略写法

  • 容器组件
1
2
3
4
5
6
7
8
9
export default connect(
(state) => ({ count: state }),
// 自动分发
{
plus: createPlusAction,
subtract: createSubtractAction,
plusAsync: createPlusAsyncAction,
}
)(CountUI);

备注:mapDispatchToProps 可传递一个包含创建 action 方法的对象,效果同未简化版本等价,类似于依赖注入。

  • 入口文件
1
2
3
4
5
6
7
8
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
{/* Provider 自动分发 store 给容器组件 */}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);

备注:Provider 组件可自动为 App 组件下的容器组件分发 redux 相关 props