Redux 介绍

本文主要是对 Redux 官方文档 的梳理以及自身对 Redux 的理解。

单页面应用的痛点

对于复杂的单页面应用,状态(state)管理非常重要。state 可能包括:服务端的响应数据、本地对响应数据的缓存、本地创建的数据(比如,表单数据)以及一些 UI 的状态信息(比如,路由、选中的 tab、是否显示下拉列表、页码控制等等)。如果 state 变化不可预测,就会难于调试(state 不易重现,很难复现一些 bug)和不易于扩展(比如,优化更新渲染、服务端渲染、路由切换时获取数据等等)。

Redux 就是用来确保 state 变化的可预测性,主要的约束有:

  • state 以单一对象存储在 store 对象中

  • state 只读

  • 使用纯函数 reducer 执行 state 更新

state 为单一对象,使得 Redux 只需要维护一棵状态树,服务端很容易初始化状态,易于服务器渲染。state 只能通过 dispatch(action) 来触发更新,更新逻辑由 reducer 来执行。

Actions、Reducers 和 Store

action 可以理解为应用向 store 传递的数据信息(一般为用户交互信息)。在实际应用中,传递的信息可以约定一个固定的数据格式,比如: Flux Standard Action
为了便于测试和易于扩展,Redux 引入了 Action Creator:

function addTodo(text) {
  return {
    type: ADD_TODO,
    text,
  }
}
store.dispatch(addTodo(text))

dispatch(action) 是一个同步的过程:执行 reducer 更新 state -> 调用 store 的监听处理函数。如果需要在 dispatch 时执行一些异步操作(fetch action data),可以通过引入 Middleware 解决。

reducer 实际上就是一个函数:(previousState, action) => newState。用来执行根据指定 action 来更新 state 的逻辑。通过 combineReducers(reducers) 可以把多个 reducer 合并成一个 root reducer。

reducer 不存储 state, reducer 函数逻辑中不应该直接改变 state 对象, 而是返回新的 state 对象(可以考虑使用 immutable-js)。

store 是一个单一对象:

  • 管理应用的 state

  • 通过 store.getState() 可以获取 state

  • 通过 store.dispatch(action) 来触发 state 更新

  • 通过 store.subscribe(listener) 来注册 state 变化监听器

  • 通过 createStore(reducer, [initialState]) 创建

在 Redux 应用中,只允许有一个 store 对象,可以通过 combineReducers(reducers) 来实现对 state 管理的逻辑划分(多个 reducer)。

Middleware

middleware 其实就是高阶函数,作用于 dispatch 返回一个新的 dispatch(附加了该中间件功能)。可以形式化为:newDispatch = middleware1(middleware2(...(dispatch)...))

// thunk-middleware
export default function thunkMiddleware({ dispatch, getState }) {
    return next => action =>
        typeof action === 'function' ? action(dispatch, getState) : next(action)
}

通过 thunk-middleware 我们可以看出中间件的一般形式:中间件函数接受两个参数参数: dispatch 和 getState(也就是说中间件可以获取 state 以及 dispatch new action)。中间件一般返回 next(action)(thunk-middleware 比较特殊,它用于 dispatch 执行异步回调的 action)。store 的创建过程如下:

const reducer = combineReducers(reducers)
const finalCreateStore = applyMiddleware(promiseMiddleware, warningMiddleware,
    loggerMiddleWare)(createStore)
const store = finalCreateStore(reducer)

异步 Actions

单页面应用中充斥着大量的异步请求(ajax)。dispatch(action) 是同步的,如果要处理异步 action,需要使用一些中间件。
redux-thunksredux-promise 分别是使用异步回调和 Promise 来解决异步 action 问题的。

Redux 和传统 Flux 框架的比较


图来自 UNIDIRECTIONAL USER INTERFACE ARCHITECTURES

Redux 和 React

Redux 和 React 是没有必然关系的,Redux 用于管理 state,与具体的 View 框架无关。不过,Redux 特别适合那些 state => UI 的框架(比如:React, Deku)。

可以使用 react-redux 来绑定 React,react-redux 绑定的组件我们一般称之为 smart componentsSmart and Dumb Componentsreact-redux 中区分如下:

Location Use React-Redux To read data, they To change data, they
“Smart” Components Top level, route handlers Yes Subscribe to Redux state Dispatch Redux actions
“Dumb” Components Middle and leaf components No Read data from props Invoke callbacks from props

简单来看:Smart component` 是连接 Redux 的组件(@connect),一般不可复用。Dumb component 是纯粹的组件,一般可复用。
两者的共同点是:无状态,或者说状态提取到上层,统一由 redux 的 store 来管理。redux state -> Smart component -> Dumb component -> Dumb component(通过 props 传递)。在实践中,少量 Dumb component 允许自带 UI 状态信息(组件 unmount 后,不需要保留 UI 状态)。
值得注意的是,Smart component 是应用更新状态的最小单元。实践中,可以将 route handlers 作为 Smart component,一个 Smart component 对应一个 reducer。

你可能感兴趣的文章

淡高 · 2015年12月17日

Flux 都还没流行起来,就变传统的了。。。。这文章写得

+5 回复

xuanyuan · 2015年10月23日

redux保存的状态刷新界面以后就没有了,请问有什么解决方案吗?

回复

ustccjw 作者 · 2015年10月25日

刷新一般是回到初始状态的,如果你有特殊需求,可以监测文档的 unload 事件,然后把 state 保存到服务器

回复

xuanyuan · 2015年11月06日

请问一下,reudx的store中是放置那些多个组件会共同用到的state呢还是应该将所有组建的state都放在store中?后面通过请求产生的最初的state,请求是应该放在action中,还是应该放在reduce中,通过initialstate来完成呢?

回复

ustccjw 作者 · 2015年11月06日

state 是在 reducer 里面维护的。所以,state 的划分存储依赖于 reducer 的划分。建议可以把共有的数据状态放在一个叫 common 的 reducer(一般就是服务器同步数据)。

数据请求一般放在 action 中,当然和服务器的数据同步可以使用 falcor/ relay 这样的方案。

回复

longxing · 2015年11月16日

请问,我在angular中使用了react,要怎么使用redux,看例子都是在跟节点上使用Provider将store引入到react中,但是在angular 中部分使用react的组件,所有没有根组件,请问解决办法

回复

ustccjw 作者 · 2015年11月16日

这个没办法解决吧,这种状态管理应该放在 angular 中更合适?因为听起来,React 只是当做 view 层解决方案部分应用在 angular 中。不过,redux 可以用于 angular 你可以找找。

回复

天可的世界 · 2016年02月04日

redux中文教程,讲解了redux的各方面,最后你会觉得redux是个“可预测”状态容器,并从中获取非凡的开发体验
https://github.com/lewis617/react-redux-tutorial

回复

碧水青鸾 · 9月13日

很不错的文章 灵魂画师!

回复

载入中...
ustccjw ustccjw

592 声望

发布于专栏

ustccjw

try to write

11 人关注