我们现在开始学习了 Redux ,在我们之前写的案例当中,我们对于状态的管理,都是通过 state 来实现的,比如,我们在给兄弟组件传递数据时,需要先将数据传递给父组件,再由父组件转发 给它的子组件。这个过程十分的复杂,后来我们又学习了消息的发布订阅,我们通过 pubsub 库,实现了消息的转发,直接将数据发布,由兄弟组件订阅,实现了兄弟组件间的数据传递。但是,随着我们的需求不断地提升,我们需要进行更加复杂的数据传递,更多层次的数据交换。因此我们为何不可以将所有的数据交给一个中转站,这个中转站独立于所有的组件之外,由这个中转站来进行数据的分发,这样不管哪个组件需要数据,我们都可以很轻易的给他派发。
而有这么一个库就可以帮助我们来实现,那就是 Redux ,它可以帮助我们实现集中式状态管理
李立超老师的解释
A Predictable State Container for JS Apps是Redux官方对于Redux的描述,这句话可以这样翻译“一个专为JS应用设计的可预期的状态容器”,简单来说Redux是一个可预测的状态容器,什么玩意?这几个字单独拿出来都认识,连到一起后怎么就不像人话了?别急,我们一点一点看。
state直译过来就是状态,使用React这么久了,对于state我们已经是非常的熟悉了。state不过就是一个变量,一个用来记录(组件)状态的变量。组件可以根据不同的状态值切换为不同的显示,比如,用户登录和没登录看到页面应该是不同的,那么用户的登录与否就应该是一个状态。再比如,数据加载与否,显示的界面也应该不同,那么数据本身就是一个状态。换句话说,状态控制了页面的如何显示。
但是需要注意的是,状态并不是React中或其他类似框架中独有的。所有的编程语言,都有状态,所有的编程语言都会根据不同的状态去执行不同的逻辑,这是一定的。所以状态是什么,状态就是一个变量,用以记录程序执行的情况。
容器当然是用来装东西的,状态容器即用来存储状态的容器。状态多了,自然需要一个东西来存储,但是容器的功能却不是仅仅能存储状态,它实则是一个状态的管理器,除了存储状态外,它还可以用来对state进行查询、修改等所有操作。(编程语言中容器几乎都是这个意思,其作用无非就是对某个东西进行增删改查)
可预测指我们在对state进行各种操作时,其结果是一定的。即以相同的顺序对state执行相同的操作会得到相同的结果。简单来说,Redux中对状态所有的操作都封装到了容器内部,外部只能通过调用容器提供的方法来操作state,而不能直接修改state。这就意味着外部对state的操作都被容器所限制,对state的操作都在容器的掌控之中,也就是可预测。
总的来说,Redux是一个稳定、安全的状态管理器。
问:不对啊?React中不是已经有state了吗?为什么还要整出一个Redux来作为状态管理器呢?
答:state应付简单值还可以,如果值比较复杂的话并不是很方便。
问:复杂值可以用useReducer嘛!
答:的确可以啊!但无论是state还是useReducer,state在传递起来还是不方便,自上至下一层一层的传递并不方便啊!
问:那不是还有context吗?
答:的确使用context可以解决state的传递的问题,但依然是简单的数据尚可,如果数据结构过于复杂会使得context变得异常的庞大,不方便维护。
Redux可以理解为是reducer和context的结合体,使用Redux即可管理复杂的state,又可以在不同的组件间方便的共享传递state。当然,Redux主要使用场景依然是大型应用,大型应用中状态比较复杂,如果只是使用reducer和context,开发起来并不是那么的便利,此时一个有一个功能强大的状态管理器就变得尤为的重要。
首先,我们先明晰 Redux 的作用 ,实现集中式状态管理。
Redux 适用于多交互、多数据源的场景。简单理解就是复杂
从组件角度去考虑的话,当我们有以下的应用场景时,我们可以尝试采用 Redux 来实现
除此之外,还有很多情况都需要使用 Redux 来实现

如上图所示,redux 通过将所有的 state 集中到组件顶部,能够灵活的将所有 state 各取所需地分发给所有的组件。
redux 的三大原则:
state 都被存储在一棵 object tree 中,并且 object tree 只存在于唯一的 store 中(这并不意味使用 redux 就需要将所有的 state 存到 redux 上,组件还是可以维护自身的 state )。state 是只读的。state 的变化,会导致视图(view)的变化。用户接触不到 state,只能接触到视图,唯一改变 state 的方式则是在视图中触发action。action是一个用于描述已发生事件的普通对象。reducers 来执行 state 的更新。 reducers 是一个纯函数,它接受 action 和当前 state 作为参数,通过计算返回一个新的 state ,从而实现视图的更新。
如上图所示,redux 的工作流程大致如下:
store.dispatch 方法发出 action。store 自动调用 reducers,并且传入两个参数:当前 state 和收到的 action。reducers 会返回新的 state 。store 监听到 state 的变化,就会调用监听函数,触发视图的重新渲染。store 就是保存数据的地方,整个应用只能有一个 store。redux 提供 createStore 这个函数,用来创建一个 store 以存放整个应用的 state:import {
createStore } from 'redux';
const store = createStore(reducer, [preloadedState], enhancer);
createStore用来创建一个Redux中的容器对象,它需要三个参数:reducer、preloadedState、enhancer。
reducer是一个函数,是state操作的整合函数,每次修改state时都会触发该函数,它的返回值会成为新的state。
preloadedState就是state的初始值,可以在这里指定也可以在reducer中指定。
enhancer增强函数用来对state的功能进行扩展,暂时先不理它。
store 对象包含所有数据。如果想得到某个时点的数据,就要对 store 生成快照。这种时点的数据集合,就叫做 state。state,可以通过 store.getState() 方法拿到:import {
createStore } from 'redux';
const store = createStore(reducer, [preloadedState], enhancer);
const state = store.getState();
state 的变化,会导致视图的变化。但是,用户接触不到 state,只能接触到视图。所以,state 的变化必须是由视图发起的。action 就是视图发出的通知,通知store此时的 state 应该要发生变化了。action 是一个对象。其中的 type 属性是必须的,表示 action 的名称。其他属性可以自由设置,社区有一个规范可以参考:const action = {
type: 'ADD_TODO',
payload: 'Learn Redux' // 可选属性
};
上面代码定义了一个名称为 ADD_TODO 的 action,它携带的数据信息是 Learn Redux。
view 要发送多少种消息,就会有多少种 action,如果都手写,会很麻烦。action,这个函数就称作 Action Creator,如下面代码中的 addTodo 函数:const ADD_TODO = '添加 TODO';
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
const action = addTodo('Learn Redux');
redux-actions 是一个实用的库,让编写 redux 状态管理变得简单起来。该库提供了 createAction 方法用于创建动作创建器:import {
createAction } from "redux-actions"
export const INCREMENT = 'INCREMENT'
export const increment = createAction(INCREMENT)
上边代码定义一个动作 INCREMENT, 然后通过 createAction
创建了对应 Action Creator:
increment() 时就会返回 { type: 'INCREMENT' }increment(10)返回 { type: 'INCREMENT', payload: 10 }store.dispatch() 是视图发出 action 的唯一方法,该方法接受一个 action 对象作为参数:import {
createStore } from 'redux';
const store = createStore(reducer, [preloadedState], enhancer);
store.dispatch({
type: 'ADD_TODO',
payload: 'Learn Redux'
});
Action Creator,这段代码可以改写如下:import {
createStore } from 'redux';
import {
createAction } from "redux-actions"
const store = createStore(reducer, [preloadedState], enhancer);
const ADD_TODO = 'ADD_TODO';
const add_todo = createAction('ADD_TODO'); // 创建 Action Creator
store.dispatch(add_todo('Learn Redux'));
store 收到 action 以后,必须给出一个新的 state,这样视图才会进行更新。state 的计算(更新)过程则是通过 reducer 实现。reducer 是一个函数,它接受 action 和当前 state 作为参数,返回一个新的 state:const reducer = function (state, action) {
// ...
return new_state;
};
store.dispatch 方法时自动执行 reducer 函数,需要在创建 store 时将将 reducer 传入 createStore 方法:import {
createStore } from 'redux';
const reducer = function