redux 是参考 Flux 设计原则的一个管理数据流的库.
下图为 redux 的核心运作流程
image
redux 三大原则:
单一数据源: 整个应用的状态都保存在一个对象 (store) 中. 这样我们随时可以取出整个应用的状态进行持久化.
状态只读: 不允许直接修改状态(必须通过 dispatch action 来修改状态)
纯函数 reducer: 状态修改为一个纯函数 (接受一定的输入, 必定会得到一定的输出) 完成.
1. Redux 核心 API
Redux 的核心是一个 store - 存储状态.
- import {
- createStore
- } from 'redux';
- const store = createStore(reducers, initialState);
store 是一个对象, 包含 4 个方法:
getState(): 获取 store 中当前的状态
dispatch(action): 分发一个 action, 并返回这个 action, 这是唯一能改变 store 中数据的方式
subscribe(listener): 注册一个监听者, 它在 store 发生变化时调用
replaceReducer(nextReducer): 更新当前 store 里面的 reducer, 一般只会在开发模式中调用该方法
我们只需要关注 getState() 和 dispatch(action) 即可.
2. 与 React 绑定使用
使用 react-redux 库.
3. Redux middleware
Redux 提供了 applyMiddleware 方法来加载 middleware.
每个 middleware 处理一个相对独立的业务需求, 通过串联不同的 middleware 实现变化多样的功能.
- export default function applyMiddleware(...middlewares) {
- return (createStore) => (reducer, preloadedState, enhancer) => {
- const store = createStore(reducer, preloadedState, enhancer)
- // 存旧的 dispatch
- let dispatch = store.dispatch
- let chain = [];
- const middlewareAPI = {
- getState: store.getState,
- // 利用匿名函数包裹 dispatch.
- dispatch: (action) => dispatch(action)
- }
- chain = middlewares.map(middleware => middleware(middlewareAPI));
- // 生成新的 dispatch
- // compose 是函数式编程中的组合, 它将 chain 中的所有匿名函数 `[f1, f2, ... , fx, ..., fn]` 组装成一个新的函数,
- // 即新的 dispatch.
- // 多个 middleware 调用结果为:`dispatch = f1(f2(f3(store.dispatch))))`;
- dispatch = compose(...chain)(store.dispatch);
- // 返回改写过 disptach 的 store
- return {
- ...store,
- dispatch
- }
- }
- }
- // 利用 applyMiddleware 创建新的 store.
- let newStore = applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, null);
在 middleware 中调用 next(action)和 store.dispatch(action)
在 middleware 中调用 next(), 可以进入下一个 middleware
在 middleware 中调用 store.dispatch(), 会跳出 middleware 流, 重新开始.
image
如上图, 分发一个 action 时, middleware 通过 next(action)一层层处理和传递 action 到 Redux 原生的 dispatch.
如果某个 middleware 使用 store.dispatch(action))分发 action, 会跳出 middleware 管道, 重新再来.
store.dispatch(action)的应用场景
action 默认都是同步的. 如果是一个异步 Action(异步请求), 那么需要一个专门处理异步请求的 middleware, 这是会用到 store.dispatch().
比如 redux-thunk:
- const thunk = store =>next => action =>
- typeof action === 'function' ? action(store.dispatch, store.getState) : next(action)
异步 Acton 设计如下: 发起异步请求, 如果成功, 弹出成功弹框, 否则, 弹出错误弹框.
- const getThenShow = (dispatch, getState) =>{
- const url = 'http://xxx.json';
- fetch(url)
- .then(response=>{
- dispatch({
- type: 'SHOW_MESSAGE_SUCCESS',
- message: response.JSON
- })
- })
- .catch(error=>{
- dispatch({
- type: 'SHOW_MESSAGE_FAIL',
- message: 'error'
- })
- })
- }
4. Redux 性能优化
使用 react-redux
在使用 react-redux 的 connect 函数时, 实际上产生了一个无名的 React 组件类, 这个类定制了 shouldComponentUpdate 函数的实现, 实现逻辑时对比这次传递给内层傻瓜组件的 props 和上次的 props. 如果 props 没有变化, 那内层组件无需再次渲染.
- import {connect} from 'react-redux';
- const Foo = ({text})=>(
- <div>{text}</div>
- )
- const mapStateToProps = (state)=> (
- text: state.text
- )
- // connect 函数返回了一个容器组件, 会实现 shouldComponentUpdate 函数, 判断这次的 text 和上一次 text 的值是否相等.
- export default connect(mapStateToProps)(Foo);
connect 函数中采用浅比较, 即 value1 == value2.
2)用 reselect 提高数据获取性能
工作原理: 只要相关状态没有改变, 就直接使用上一次的缓存结果.
reselect 把计算过程分为两个步骤:
步骤 1: 从输入参数 state 抽取第一层结果, 第一层结果和之前抽取的第一层结果做比较(=== 比较), 如果发现完全相同, 就不会进入第二步计算, 选择器直接把之前第二部分的运输结果返回.
步骤 2: 根据第一层结果计算出选择权需要返回的最终结果.
定义选择器:
- import { createSelector } from 'reselect'
- const getVisibilityFilter = (state) => state.visibilityFilter
- const getTodos = (state) => state.todos
- export const getVisibleTodos = createSelector(
- [ getVisibilityFilter, getTodos ],
- (visibilityFilter, todos) => {
- switch (visibilityFilter) {
- case 'SHOW_ALL':
- return todos
- case 'SHOW_COMPLETED':
- return todos.filter(t => t.completed)
- case 'SHOW_ACTIVE':
- return todos.filter(t => !t.completed)
- }
- }
- )
使用新定义的选择器:
- import {getVisibleTodos} from './selector.js'
- const mapStateToProps = (state) => {
- return {
- todos: getVisibleTodos(state);
- }
- }
- 3)Immutable Redux
持久化数据结构, 结构共享, 惰性操作.
通过 Immutable.JS 创建的对象在任何情况下都无法被修改, 这样可以防止由于开发者的粗心导致直接修改 Redux 的 state.
微信公众号:
来源: http://www.jianshu.com/p/8080025c4ec3