redux使用

2021-05-02 REACT 大约 5 分钟

Redux 是 JavaScript 状态容器,提供可预测化的状态统一管理。 它不是react独有的,任何地方都可以用:原生jsjQeryvue等。

三大原则:

  1. 单一数据源。
  2. State 是只读的。
  3. 使用纯函数来执行修改。

相关信息

Redux 是负责组织 state 的⼯具,但你也要考虑它是否适合你的情况。不要因为有⼈告诉你要⽤ Redux 就去⽤,花点时间好好想想使⽤了 Redux 会带来的好处或坏处。 在下⾯的场景中,引⼊ Redux 是⽐较明智的:

  • 你有着相当⼤量的、随时间变化的数据;
  • 你的 state 需要有⼀个单⼀可靠数据来源;
  • 你觉得把所有 state 放在最顶层组件中已经⽆法满⾜需要了。
  • 某个组件的状态需要共享。

image-20220102141647689

# 安装

  • 通过标签引入;

    <script src="../node_modules/redux/dist/redux.js"></script>
    
    const { Redux } = window  // 要结构出来使用;
    
    1
    2
    3
  • 通过npm包管理。

    # 安装;
    npm install --save redux
    
    # 引入;
    import { createStore } from 'redux';
    
    1
    2
    3
    4
    5

# 基础

在使用redux的过程中,你需要了解下以下几个概念:

# Action

Action是把数据从应用传到 store 的有效载荷,它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() (opens new window) 将 action 传到 store。 本质上是javaScript的普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作 。 多数情况下,type 会被定义成字符串常量。建议使用单独的模块或文件来存放 action。

// 添加新 todo 任务的 action :
const ADD_TODO = 'ADD_TODO'

const action1 = {
  type: ADD_TODO,
  text: 'Build my first Redux app'
}
1
2
3
4
5
6
7
// 单独的模块统一管理存放 action;
import { ADD_TODO } from '../actionTypes'
1
2

# Action创建函数

概述: Action 创建函数 就是生成 action的方法 。

// action 创建函数只是简单的返回一个 action:
function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}
1
2
3
4
5
6
7
// actions.js
/*
 * action 类型
 */

export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'

/*
 * 其它的常量
 */

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
}

/*
 * action 创建函数
 */

export function addTodo(text) {
  return { type: ADD_TODO, text }
}

export function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

export function setVisibilityFilter(filter) {
  return { type: SET_VISIBILITY_FILTER, filter }
}
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
34

# Reducer

Reducers 指定了应用状态的变化如何响应 actions (opens new window) 并发送到 store 的,注意 actions 只是说明了有事情发生了这一事实,并没有说明应用如何更新 state。

  • 设计state结构; 所有的 state 都被保存在一个单一对象中 。

  • Action处理; 确定了 state 对象的结构,就可以开发 reducer。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。

// reducers.js

import { combineReducers } from 'redux'
import {
  ADD_TODO,
  TOGGLE_TODO,
  SET_VISIBILITY_FILTER,
  VisibilityFilters
} from './actions'

const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

// 和下面等价
const todoApp = combineReducers({
  visibilityFilter,
  todos
})

//export default function todoApp(state = {}, action) {
//  return {
//    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
//    todos: todos(state.todos, action)
//  }
//}

export default todoApp
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

开发一个函数来做为主 reducer,它调用多个子 reducer 分别处理 state 中的一部分数据,然后再把这些数据合成一个大的单一对象。主 reducer 并不需要设置初始化时完整的 state。初始时,如果传入 undefined, 子 reducer 将负责返回它们的默认值。

注意

  • 不要reduce里修改传入的参数。
  • 不要执行有副作用的操作,如 API 请求和路由跳转;
  • 不要 调用非纯函数,如 Date.now()Math.random()
  • 每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。

# Store

Store 就是把它们联系到一起的对象。Store 有以下职责:

创建 store

// src导入方式: const { Redux: {createStore} } = window

// 包引入方式;
import { createStore } from 'redux'
import todoApp from './reducers'
import {
  addTodo,
  toggleTodo,
  setVisibilityFilter,
  VisibilityFilters
} from './actions'

// 创建仓库;
let store = createStore(todoApp)

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

// 每次 state 更新时,打印日志。注意 subscribe() 返回一个函数用来注销监听器
const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

// 发起一系列 action
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))

// 停止监听 state 更新
unsubscribe();
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

相关信息

redux 的值更新之后你需要使用subscribe监听,然后做其他的事情,例如重新renderDOM

注意

  • 再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 (opens new window) 而不是创建多个 store。
  • 使用store.dispatch(action)action必须是对象且拥有type属性,否则会报错。

# 示例

todoList点击前往 (opens new window)

# 扩展

# 什么是reducer

reducer 就是⼀个纯函数,接收旧的 state 和 action,返回 新的 state。

;(previousState, action) => newState
1

之所以将这样的函数称之为 reducer,是因为这种函数与被 传⼊ Array.prototype.reduce(reducer, ? initialValue) ⾥的回调函数属于相同的类型。

相关信息

保持 reducer 纯净⾮常重要。永远不要在 reducer ⾥做这些操 作:

  • 修改传⼊参数;
  • 执⾏有副作⽤的操作,如 API 请求和路由跳转;
  • 调⽤⾮纯函数,如 Date.now() 或 Math.random()。

# 什么是reduce 点击前往 (opens new window)

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
1
2
3
4
5
6
7
8
上次编辑于: 2023年7月4日 09:36