引言
根据官网介绍,Redux 是一个 JavaScript 状态管理容器,提供了可预测的状态管理能力。可以构建一致的应用,运行于多种环境下(客户端、服务器和原生应用等),且易于测试(甚至都不要在写界面之前进行测试)。
概念
核心思想
Redux 的核心就是管理状态,所有的状态是在 store 对象树中维护。使用 action 来描述 state 变化,而为了能够将 action 和 state 串联在一块,就有了 reducer 函数,它负责根据不同的 action dispatch 到不同的分支,然后返回新的状态。需要注意的是,reducer 是纯函数,不应该 inplace 那种方式修改 state,而是生成新的 nextState 并返回。
通常一个应用中可能有多个小的 reducers ,我们可以使用 combineReducers
将它们组合在一起。
三大原则
- 单一数据源:整个应用的 state 是存储在一个 obj tree 中的,并且该 obj tree 只存在于唯一一个 store 中
- state 是只读的:唯有触发 action 才会改变 state,使用 action 来描述发生了什么
- 使用纯函数执行修改:需要编写 reducer 实现状态改变
三驾马车
Action
- Action 是把数据从应用传递到 store 的有效载荷,是 store 数据的唯一来源
- 一般通过
store.dispatch()
分发 action,传递到 store - 当应用规模变大时,建议将 Action 使用单独的模块存放
- 尽量减少在 action 中传递的数据
- Action 创建函数:返回 action 的函数,使用
bindActionCreators()
可以自动将多个 action 创建函数绑定到dispatch()
方法上 - Action 只是描述了有事情发生了这样的事实,但不会描述应用如何更新 state
Reducer
- 在 reducer 中响应 action,并产生新的 state,达到改变 state 的目的
为什么叫 reducer?参考
Array.prototype.reduce(reducer, ?initialValue)
里面的回调函数,它们比较类似,都必须是纯函数。reducer 函数不欢迎如下操作:- 修改传入参数
- 执行含有副作用的操作,如 API 请求和路由跳转
- 调用非纯函数,如
Date.now()
或Math.random()
可以把所有顶级 reducer 放在独立的文件中,通过
export
暴露每个 reducer 函数:1
2
3
4import { combineReducers } from 'redux'
import * as reducers from './reducers'
const todoApp = combineReducers(recuders)
Store
Store 的职责如下:
- 维持应用的 state
- 提供
getState()
读取状态 - 提供
dispatch(action)
方法更新状态
-提供subscribe(listener)
方法注册监视器,其返回的函数用于注销监视器
Redux 应用的 store 只会有一个,一般会根据业务逻辑来拆分子状态分组,可以通过
reducers
组合完成createStore(reducer, ?initialState)
创建应用 store
示例
1 | import React, { useRef } from 'react' |
实践
按照 Redux 提供的几个官方示例,可以看出编写一个简单的 Todo 应用其实要考虑的还是挺多的,尤其是需要在分散的模块中分别定义 actions, reducers, containers, dumb components 等,然后搭配 react-redux 来实现整体功能。
以下是一个经典的 React Redux 应用的示例的文件结构:
1 | src/ |
看起来,分层结构很明晰。但这里有几个很大的问题:
- components 和 containers 可能会出现相互引用的问题;
- 对于某些情形,严格区分 smart components 和 dumb components 比较死板;
- 编写起来很复杂、啰嗦、冗余。
针对这个痛点,可以借助 rematch 框架解决。它本质上是一个基于 Redux 封装的框架,目的是提供最佳的 Redux 实践,减少大量的样板代码编写,解放生产力!
使用 Rematch 时,有个非常重要的概念叫做 model
。你可以在 models
里面将状态、引起状态变化reducers 及异步 actions 和 action creators 收敛到一起,方便维护和测试。总的来说,model
定义包含如下几个部分:
- state: 初始状态是什么
- reducers: 如何改变状态
- effects: 处理异步的 actions,带有副作用的操作
一个典型的 model 定义如下:
1 | export const count = { |
有了 models 后,就可以创建 Redux store,并使用 dispatch
来触发 reducers 和 effects 调用(无需手动编写 action creators 啦~)。当然,在展示层,我们依然可以结合 react-redux 来使用。具体可以参考官方示例,更详细的文档可以参考 这里。
参考
- Redux 官网文档
- Redux 中文译文
- Redux 入门视频教程
- 以地道的方式使用 Redux 构建 React 应用
- Redux and Why it’s Good For You
- What Does Redux Do
- Presentational and Container Components,作者其实已经不推荐这种写法了
- React Redux 官方文档