美文网首页
理解Redux

理解Redux

作者: 片虚 | 来源:发表于2016-11-14 23:34 被阅读0次

从 React 说起

刚开始接触 React 的时候其实是感到非常惊艳的,在 React 的架构下可以像搭积木一样把前端的视图组件组合在一起,非常好玩,React 这种模块化的结构保证了组件内部的高度自治性,使得前端开发高度正交化。以至于刚刚使用 React 的时候简直觉得是在上帝之手的帮助之下写前端,触手丝滑,效率飞起,但是用了一段时间之后就很快发现了一些问题,比如父组件可以通过给子组件赋值 props,但是子组件向父组件传值却只能通过较为复杂的双向绑定,如果要向不是父子关系的组件传值怎么办呢?React 的文档会告诉你只能再 copy 一个组件过来了。EXM?组件之间传值这么常见的操作 React 却只能给出一个这么简单粗暴的办法?负分!差评!

但是知道了 Redux 这么一个神奇的存在之后,感觉 React 终于有救了,在 Redux 的框架之下,所有的状态被集中起来统一管理,使得应用内的数据完美地同步起来,再也不用担心组件之间的通讯问题了。

当然这里要提一下,Redux 本身是一个单独的框架,跟 React 没什么关系,但是由于在 React 的框架下视图和 state 和 view 是一一对应的,这样就使得 Redux 更适用于 React 环境下的开发。

Redux 的基本思想

Redux 是一个基于Flux思想实现的一个针对web应用的状态管理库,在Redux 里 Web 应用被视为一个有穷状态机,在这个状态机里所有状态的变化都是可以追溯甚至是可以撤销的,为了实现这样的机制,Redux 进行了以下三个约束:

  • 所有的 state 构成一棵 object tree,这棵 object tree 只存在于唯一一个store 中。
  • 所有state都是只读的,唯一改变 state 的方法是触发 action
  • 使用纯函数来执行修改,以保证每次对状态修改的执行结果都是一致的

在 redux 中主要引入了 action、reducer、store 这三个概念,action 用于定义一个请求,reducer 用于根据 action 产生新状态,store 用于存储和管理 state,监听 action,将 action 自动分配给 reducer 并根据 reducer 的执行结果更新 state。

在这里你可以根据字面意思把 store 想象成一个仓库,这个仓库里的货物就是 state ,但是这个仓库的管理员实在是懒得跟自己的客户沟通,就请了好几个助手来帮自己,比如助手 A 专门负责某个手机厂商的请求,助手B专门负责电脑厂商的请求,他们计算好进出货量之后通知管理员,管理员如果接到手机厂商的请求就把他分配给 A,接到电脑厂商的请求就分配给B,得到 A 和 B 的结果之后管理员就可以马上更新仓库了,在这里这些助手就是 reducer,像手机和电脑厂商的请求就是 action。执行任务分配的这个过程就是 store.despatch(action) 函数 。

Redux 的基本概念

Action

action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。用来表明一个事件的发生,但并不对状态如何修改做任何描述。一个action 的结构是一个 javascript 普通对象,一个 action 的结构如下

{
  //type字段用于标识action的类型,一般用一个字符串来表示
  type: 'ADD_TODO', 
  //text是用户自定义的字段,一般用来传递和状态修改相关的参数
  text: 'Build my first Redux app'
}

Reducer

action 只是描述了有事情发生了这一事实,但是并没有指名如何更新 state,reducer 就是对状态修改过程的描述,但是需要注意的有以下两点:

  • 由于状态是只读的,reducer 本身并不能真正实现状态的修改,而是只把新状态作为返回值返回。

  • 为了确保每次对状态修改的结果都是一致的,reducer 必须是一个纯函数,也就是说,只要是同样的输入,必定得到同样的输出。纯函数需要遵循以下约束:

    不得改写参数
    不能调用系统 I/O 的API
    不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果
    

    一个 reducer 的结构如下

/* 在这个 reducer 中,对于一个类型为 ADD_TODO 的 action,返回的新状态是在传入状态数组中追加了一个元素 */
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
      default:
          return state
  }
}

Store

在定义了描述事件发生的 action 和描述状态修改方案的 reducer 之后,如何把它们联系到一起真正实现状态的改变呢?这就要牵扯到 store 啦,前面已经提过 redux 的原则之一就是所有的 state 构成的对象树都存到了 store 中,除此之外 store 还有以下功能:

  • 维持应用的 state
  • 提供 getState() 方法获取 state
  • 提供 dispatch(action)方法更新 state;
  • 通过 subscribe(listener)注册监听器;
  • 通过 subscribe(listener)返回的函数注销监听器。

创建一个 store 其实很简单:

import { createStore } from 'redux'
import reducers from './reducers'
let store = createStore(reducers)

createStore() 的第二个参数是可选的, 用于设置 state 初始状态。这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。

let store = createStore(todoApp, window.STATE_FROM_SERVER)                                                                                                                                                                                                                                                                                                                                                                                                                                   

接下来就可以简单实现一个创建处理 action 的过程了

import { createStore } from 'redux'
const ADD_TODO = 'ADD_TODO' 
//创建一个 action 
const simpleAction1 = {
  type: 'ADD_TODO', 
  text: 'Build my first Redux app'
}
const simpleAction2 = {
  type: 'ADD_TODO', 
  text: 'Build my second Redux app'
}
//创建一个 reducer, 功能为收到类型为 ADD_TODO 的 action 后为在 state 中添加一个条目
function reducer(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
      default:
          return state
  }
}
//创建一个初始状态为空数组的 store 
let store = createStore(reducer,[])

// 打印初始状态
console.log(store.getState())

// 每次 state 更新时,打印日志
// 注意 subscribe() 返回一个函数用来注销监听器
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)
// 发起一个 action, 执行之后会更新状态,由于注册了监听器你可以看到每次更新都会打印当前状态
store.dispatch(simpleAction1)
store.dispatch(simpleAction1)

// 停止监听 state 更新
unsubscribe();

相关文章

网友评论

      本文标题:理解Redux

      本文链接:https://www.haomeiwen.com/subject/cpjkpttx.html