Redux 学习

概念

Redux 是一个可以预测的JavaScript 状态控制器,专注于状态管理,有store,state, action,reducer 等API(类似 vue 中的 vux)

Redux 可编写构建行为状态一致的应用,可运行在客户端、服务的 和 原生应用 环境中,并且容易测试。 最重要的是,它提供很好的开发体验,编译后的代码可通过devtools实时预览调试。

Redux 可以和 React 一起使用,也可以和其他视图库(如 Vue)使用。它很小(2K大小 包含依赖 ),并且有一个庞大的插件生态系统。

安装

使用 npm

1
npm install redux -S

使用 yarn

1
yarn add redux -P

使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 引入 redux
import {createStore} from 'redux'

const ADD_NUM = 1;
const SUB_NUM = 2


// 创建 redecer
const counter = (state = 6,action)=>{
switch(action.type){
case ADD_NUM:
return ++state
case SUB_NUM:
return --state
default:
return state
}

}
// 创建 store
const store = createStore(counter)
// 获取state
const num = store.getState()
// 发布信息更改state
store.dispatch({type:1})

// 订阅 获取state
store.subscrible(lister) // 没执行一次dispatch (改变state) 就执行一次 lister 方法
// 设置每次state变化 后的行为
function lister(){
console.log(store.getState())
}
store.dispatch({type:0})

核心概念

更新state中的数据,须通过action(就是一个普通对象) 来更改,这样可清晰的知道应用中发生了什么,数据为什么变动,怎样变动。而核心想法是如何根据这些 action 对象来更新 state。

1
2
{type:1}
{type:2}

将state和action结合成函数,这就是reducer。它只接受 state和action 两个参数,并返回新的state函数。

1
2
 console.log(store.getState())// 6
}

当然一个应用不单单只有一个reducer,我们可以通过redux来将它们合并。

Redux 三大原则

单一数据源 (Single source of truth)

整个应用程序的 state 存储在一个单一 store 的对象树(object tree)中

这样更容易创建创建通用应用,来自服务端的 state 可以在无需编写更多代码的情况下被序列化并注入到客户端中。这样单一的 state 树更容易调试和检查。它还能在开发过程中保持应用程序的状态,从而加快开发周期。一些在传统上难以实现的功能(撤销/重做),将其state 存储在树中,从而变得更加简单。

1
2
3
4
5
6
7
store.dispatch({
type: 1
})

store.dispatch({
type: 2
})

State 是只读的 (State is read-only)

改变state的唯一方法是触发 action, action是描述发生什么事件的对象

这样确保视图和网络请求不会直接修改state,反而,它们明确表达想要修改的意图。因为所有的变化都被集中处理,且按照严格的顺序一个接一个执行。所以没有细微的竞争条件需要注意。 Action是一个普通对象,所以可以对它们进行打印、序列化、存储,然后后期调试和测试。

1
2
3
4
5
6
7
store.dispatch({
type: 1
})

store.dispatch({
type: 2
})

使用纯函数进行更改

要如何通过 action改变指定的state tree ,需要编写 Reducers 函数

Reducer 只是一些纯函数,他接收 state 和 action 两个参数,并且返回新的state ,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { combineReducers, createStore } from 'redux'
// 创建 redecer
const counter = (state = 6,action)=>{
switch(action.type){
case ADD_NUM:
return ++state
case SUB_NUM:
return --state
default:
return state
}

}
const counter1 = (state = 6,action)=>{
switch(action.type){
case ADD_NUM:
return ++state
case SUB_NUM:
return --state
default:
return state
}

}
const reducers = combineReducers({ counter, counter1 }) // 通过 combineReducers 合并reducer
const store = createStore(reducers)

基础教程

Action

Actions 是将数据从应用程序发送到 store 的有效负载。它们是store 的唯一数据来源,通过 store.dispatch() 传递给 store
example:

1
2
3
4
5
6
const ADD_TODO = 'ADD_TODO'

{
type: ADD_TODO,
text: 'Build my first Redux app'
}

Actions 本质上是普通对象。并且该对象必须有一个type 属性来表示将要执行的动作,通常 type 被定义成字符串常量。当规模变大时,可以存放到单独的文件种管理。

1
import { ADD_TODO, REMOVE_TODO } from '../actionTypes'

注意:使用单独的模块或文件定义 常量type不是必须的,对于小应用来说,使用字符串type方便。而在大型项目种定义常量利大于弊。

出了type属性外其他属性可自行定义,对于规范参考Flux Standard Action

创建 Action 的生产函数

即生成action 的方法,函数返回一个 action 对象这样更容易被移植和测试

1
2
3
4
5
6
function addTodo(text){
return {
type:ADD_TODO,
text
}
}

传统的Flux实现中调用 action 实现方法时,一般会触发一个dispatch

1
2
3
4
5
6
7
function addTodo(text){
const action= {
type:ADD_TODO,
text
}
dispatch(action)
}

Redux 中只需把action 函数传递给dispatch()

1
2
3
4
5
6
7
function addTodo(text){
return {
type:ADD_TODO,
text
}
}
store.dispatch(addTodo(text))

异步 Action

当调用异步 API时,发送请求和响应(可能超时),都可能会更改 state;因此需要 同步地 dispatchreduce 处理的操作
通常需要对应三种 action:

  • 通知 reducer 请求开始的action:reducer 可能会切换state中的 flag,来更改UI状态。
  • 通知 reducer 请求成功的action:reducer 可能会将接收到的数据合并到 state 中,并更改 flag,控制 UI。
  • 通知 reducer 请求失败的action:reducer 可能会重置 flag,并将一些失败在UI中信息显示出来

至于flag如何定义完全取决于开发者,使用多个type会降低出错几率。

1
2
3
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }

注意:在实际应用中,网络请求失败时也需要 dispatch action。

待续。。。

--------------------- Thank you for reading ---------------------