Redux 是什么
Redux 是 JavaScript 状态容器, 提供可预测化的状态管理.
它认为: web 应用是一个状态机, 视图与状态一一对应. 从架构层面来说, 通常希望 UI 跟数据, 逻辑分离, 直观体现就是: UI = render(state)
为什么要用 Redux
现在的 Web 应用涉及大量数据交互, 异步操作等, 无疑都在增加前端的复杂性, 需要维护的 state 也越来越多. 而 Redux 就是试图让每个 state 变化都是可预测, 将应用中所有的 action 与 state 统一管理.
Redux 的三原则
单一数据源 整个应用 state 应该只存储在唯一一个的 Store 中.
保持状态只是只读 不能直接修改 state, 唯一能改变 Store 的 state 方法就是通过触发一个 action 对象完成.
数据改变通过纯函数完成 action 改变 state 需要通过 reducers.
Redux 工作流程
在讲 Redux 的工作流程之前, 需了解几个 Redux 相关的核心概念:
Action:Action 可以看成是应用发出的通知, 表示 State 应该要发生变化了, Action 的触发可能是用户对 View 层的操作也可能是服务器的响应.
Action Creator: 如果有很多种 Action, 而每种 Action 都手写的话显得麻烦, 所以用定义的 Action Creator 函数来生成 Action.
Dispatch:Action 发出的唯一方法.
Store: 整个应用唯一保存数据的地方.
State: 对 Store 中保存数据生成某个时点数据快照, 该数据集合叫做 State.
Reducer:Action 只是描述了 State 应要发生变化, 而 Reducer 做的是如何改变 State.
具体工作流程: 用户通过 View(或服务器响应) 触发 Action,Dispatch 方法将 Action Creator 函数生成的 Action 派发到 Store,Store 自动调用 Reducer, 并向它传入当前 State 和 Action,Reducer 返回新的 State,State 一旦有变化, Store 就会通过监听函数来更新 View. 借用一张图来描述这一过程:
严格的单向数据流是 Redux 架构的设计核心.
几个 Redux 核心概念实例
以从服务器响应文章内容为例 Action
- const LOAD_ARTICLES_DETAIL = 'LOAD_ARTICLES_DETAIL'
- const LOAD_ARTICLES_DETAIL_SUCCESS = 'LOAD_ARTICLES_DETAIL_SUCCESS'
- const LOAD_ARTICLES_DETAIL_ERROR = 'LOAD_ARTICLES_DETAIL_ERROR'
- Action Creator
- export const loadArticlesDetail = () => ({
- type: LOAD_ARTICLES_DETAIL
- })
- export const loadArticlesDetailSuccess = result => ({
- type: LOAD_ARTICLES_DETAIL_SUCCESS,
- result
- })
- export const loadArticlesDetailFailure = error => ({
- type: LOAD_ARTICLES_DETAIL_ERROR,
- error
- })
- Store
- const store = createStore(reducers)
- Reducer (previousState, action) => (newState)
- export default (state = initalState, action) => {
- switch (action.type) {
- case LOAD_ARTICLES_DETAIL: {
- return {
- ...state,
- loading: true,
- error: false
- }
- }
- case LOAD_ARTICLES_DETAIL_SUCCESS: {
- return {
- ...state,
- loading: false,
- error: false,
- articlesDetail: action.result
- }
- }
- case LOAD_ARTICLES_DETAIL_ERROR: {
- return {
- ...state,
- loading: false,
- error: true
- }
- }
- default:
- return state
- }
- }
深入到 Redux 的源码
Redux 主要源码整体结构:
入口文件 index.js
- export {
- createStore,
- combineReducers,
- bindActionCreators,
- applyMiddleware,
- compose
- }
这是入口文件导出的方法, 也是 Redux 支持的方法, 这些方法的实现在主工作流程文件和辅助函数文件, 接下来看主工作流程.
主工作流程文件 createStore.js createStore 方法主要是生成 Store, 看看它做了哪些事儿:
getState 方法返回了当前 State
subscribe 方法传入函数到监听队列和返回取消订阅函数
dispatch 方法调用 Reducer, 按顺序执行 listener, 返回 Action 辅助源码文件:
applyMiddleware.js: 用于增强 Store
- export default function applyMiddleware(...middlewares) {
- return (createStore) => (reducer, preloadedState, enhancer) => {
- const store = createStore(reducer, preloadedState, enhancer)
- let dispatch = store.dispatch
- let chain = []
- const middlewareAPI = {
- getState: store.getState,
- dispatch: (...args) => dispatch(...args)
- }
- chain = middlewares.map(middleware => middleware(middlewareAPI))
- dispatch = compose(...chain)(store.dispatch)
- return {
- ...store,
- dispatch
- }
- }
- }
从源码上看, 最后是返回了一个 Store 和一个被更新过的 dispatch 方法, 实现了对 Store 的增强.
- bindActionCreators.js:
- export default function bindActionCreators(actionCreators, dispatch) {
- if (typeof actionCreators === 'function') {
- return bindActionCreator(actionCreators, dispatch)
- }
- }
使用 dispatch 把 action creator 都包装起来, 这样可以直接调用它们.
combineReducers.js: 当应用比较大的时而拆分 Reducer, 但是传入 Store 的 Reducer 必须是一个函数, 所以这个方法的主要功能是用来合并多个 Reducer.
- compose.js
- export default function compose(...funcs) {
- if (funcs.length === 0) {
- return arg => arg
- }
- if (funcs.length === 1) {
- return funcs[0]
- }
- return funcs.reduce((a, b) => (...args) => a(b(...args)))
- }
compose 这个方法, 传入的一系列函数, 执行的最终结果是把各个函数串联起来.
总结:
Redux 是 JavaScript 状态容器, 提供可预测化的状态管理.
严格的单向数据流是 Redux 架构的设计核心.
UI = render(state)
来源: https://juejin.im/post/5af54a59f265da0b95272835