简介
Redux
是一个可预测的 JavaScript
应用状态管理容器,也可以说是一个应用数据流框架。
作用
Redux
主要是用作应用状态的管理。它抽离所有组件的状态,构造一个中心化的单独常量状态树(对象)来保存这一整个应用的状态。这棵状态树与 React
组件树一一对应,相当于对 React
组件树进行了状态化建模:
- redux可以无视组件层级;
- 对于组件系统来说,redux就是一个第三方的,全局的“变量”。
特性
- 可预测
Redux
可以开发出行为稳定可预测、可运行在不同环境 (客户端、服务端和原生程序)且易于测试的应用。 - 集中管理
集中式存储和管理应用的状态,可以开发出强大的功能,如撤销/重做、 状态持久化等等。 - 可调试
Redux DevTools
可以轻松追踪到应用的状态在何时、何处以及如何改变。 - 数据流清晰
Redux
的架构可以记下每一次改变,借助于 “时间旅行调试”,甚至可以把完整的错误报告发送给服务器。 - 灵活
Redux
可与任何UI
层框架搭配使用,并且有庞大的插件生态。
学习文档
Redux 中文官网
优点
在应用中使用 Redux
有如下好处:
- 预测
始终有一个准确的数据源,就是store
,对于如何将actions
以及应用的其他部分和当前的状态同步可以做到绝不混乱。 - 维护
具备可预测结果的性质和严格的组织结构让代码更容易维护。 - 组织
对代码应该如何组织更加严苛,这使代码更加一致,对团队协作更加容易。 - 测试
编写可测试代码的首要准则就是编写可以仅做一件事并且独立的小函数。Redux
的代码几乎全部都是这样的函数:短小、纯粹、分离。 - 服务端渲染
可以带来更好的用户体验并且有助于搜索引擎优化,尤其是对于首次渲染。仅仅是把服务端创建的store
传递给客户端就可以。 - 开发者工具
开发者可以实时跟踪在应用中正在发生的一切,从actions
到状态的改变。 - 社区与生态圈
存在很多支持Redux
的社区,使它能够吸引更多的人来使用。
核心概念
Redux
核心概念有三个:action、store、reducer
。
store
在 Redux
里面, Store
是一个仓库,整合 action
和 reducer
,用来保存整个应用需要管理的数据 state
。(与vuex
的 store
意义上相似)
Redux
提供了一个 createStore
来创建 state
。如下:
import { createStore } from 'redux';
// 创建 store
let store = createStore(rootReducer);
let authInfo = {username: 'admin', password: '123'};
store.dispatch(authUser(authInfo));
createStore
函数接受另一个函数作为参数,返回新生成的 Store
对象。
store
特点
- 有且仅有一个
store
- 维护应用的状态,获取状态:
store.getState()
- 创建
store
时接收reducer
作为参数:const store = createStore(reducer)
- 发起状态更新时,需要分发
action:store.dispatch(action)
store.getState()
store.getState()
:获取 store
中存储的值
store.dispatch(action)
store.dispatch(action)
:派发动作,参数是一个动作对象 { type: 'xxx', data: xxx }
store.subscribe()
store.subscribe()
:Store
允许使用 store.subscribe
方法设置监听函数监听store
值的变化,一旦 State
发生变化,就自动执行这个函数。
在单个组件内监听 store
的状态变化:
// redux只维护状态,但是不会触发页面更新(不会触发组件render的调用)
// 检测redux中状态的变化,就调用render
store.subscribe(() => {
this.setState({}); // 传入空对象,只为触发组件的render方法
});
如果每个组件都需要监听 store
,则可以在 index.js
入口文件监听 store
,有变化则重新渲染 app
组件。
由于
react
有diff
算法,如果组件没有变化,不会更新所有的组件,不会引起页面重绘重排,所以不用担心效率问题。
解除监听
store.subscribe
方法返回一个函数,调用这个函数可以解除监听。
如下:
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
);
unsubscribe();
actions(动作)
Actions
就是事件,传递来自这个应用的视图层发起的一个操作(比如用户接口,内部事件比如 API
调用和表单提交),告诉 store
需要改变 state
。
Actions
提交数据给 store
,store
只获取来自 Actions
的信息。
Action
描述了 action
的类型以及传递给 store
的负载信息,它有两个属性:
(1) type
(通常是常量):标识属性,表示 action
的名称;
(2) payload
:数据属性,可选。可以带一些参数,表示本次动作携带的数据,用作 Store
变更。
如下:
{
type: LOGIN_FORM_SUBMIT,
payload: {username: 'admin', password: '123'}
}
如上所示,定义了一个名为 LOGIN_FORM_SUBMIT
的 Action
,还携带了payload
的参数。
Action Creator
View
要发送多少种消息,就会有多少种 Action
。在Redux
中,可以用 Action Creator
生成器来批量生成一些 Action
:
function authUser(form) {
return {
type: LOGIN_FORM_SUBMIT,
payload: form
}
}
store.dispatch()
Action
不会自己主动发出变更操作 Store
,在应用中需要使用 dispatch
方法来调用 actions
,它专门用来发出action
:
dispatch(authUser(form));
在 Redux
里面,store.dispatch()
是 View
发出 Action
的唯一方法。
action
特点
- 只描述做什么;
JS
对象,必须带有type
属性,用于区分动作的类型;- 根据功能的不同,可以携带额外的数据,配合该数据来完成相应功能。
reducers
当 store.dispatch
发起了一个 action
之后,会到达 reducer
,reducer
获得这个应用的当前状态和事件并完成,经过计算,返回一个新的 state
状态对象给 store
(这使得 Redux
非常简单以及可预测)。
在函数式
JavaScript
中reducer
基于数组reduce
方法,接收一个回调(reducer
)可以从多个值中获得单个值,整数和,或者一个一系列值的累积。
如下:
function handleAuth(state, action) {
return _.assign({}, state, {
auth: action.payload
});
}
对于更多复杂的项目,推荐使用
Redux
提供的combineReducers()
实例。它把在这个应用中所有的reducer
结合在一起成为单个索引reducer
。每一个reducer
负责它自己那部分应用的状态,这个状态参数和其他reducer
的不一样。combineReducers()
实例使文件结构更容易维护。
如下:
const rootReducer = combineReducers({
handleAuth: handleAuth,
editProfile: editProfile,
changePassword: changePassword
});
如果一个对象
(state)
只改变一些值,Redux
就创建一个新的对象,那些没有改变的值将会指向旧的对象而且新的值将会被创建。这对性能是极好的。为了让它更有效率可以添加Immutable.js
。
reducer
特点
- 是一个纯函数,可查看之前的状态,执行一个
action
并返回一个新的状态; - 接收两个参数:当前的
state
和接收到的action
,返回一个新的state
。
纯函数的意思是说,对于相同的输入,只会有相同的输出,不会影响外部的值,也不会被外部的值所影响。