0%

redux

概念:

Redux 是一个使用”actions”的事件管理和更新应用状态的模式和工具库,以集中式Store的方式对整个应用中使用的状态进行集中管理,其规则确保状态只能以可预测的方式更新

Redux 在以下情况下更有用:

  • 在应用的大量地方,都存在大量的状态
  • 应用状态会随着时间的推移而频繁更新
  • 更新该状态的逻辑可能很复杂
  • 中型和大型代码量的应用,很多人协同开发

store:

保存应用程序的全局state的容器,是一个Js对象,store是通过传入一个reducer来创建的,并且有一个名为getState的方法,它返回当前状态值

1
2
3
4
import {configureStore} from "@reduxjs/toolkit"
const store=configureStore({reducer:counterReducer})
console.log(store.getState())
//{value:0}

action:

是一个具有type字段的普通js对象,可以将action视为描述应用程序中发生了什么事件,type字段是一个字符串,给这个action一个描述性的名字,比如”todos/todoAdded”(域/事件名称),第一部分是这个action所属的特征和类别,第二部分是具体发生的具体事情

action对象可以有其他字段,将其放在名为payload的字段中

action创建函数:就是生成action的方法,action创建函数只是简单返回一个action

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

reducers

reducer是一个函数,接收当前的state和一个action对象,必要时决定如何更新状态,并返回新状态,函数签名(state,action)=>newState,可以将reducer视为一个事件监听器,它根据接收到的action类型处理事件

reducer必须是一个纯函数:

  • 仅使用 stateaction 参数计算新的状态值
  • 禁止直接修改 state。必须通过复制现有的 state 并对复制的值进行更改的方式来做 不可变更新(immutable updates)
  • 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码

reducer 函数内部的逻辑通常遵循以下步骤:

  • 检查 reducer 是否关心这个 action
    • 如果是,则复制 state,使用新值更新 state 副本,然后返回新 state
  • 否则,返回原来的 state 不变

dispatch

更新state的唯一方法是调用store.dispatch()并传入一个action对象,store将执行所有reducer函数并计算出更新后的state,调用getState()可以获取更新的state

1
2
3
store.dispatch({type:'counter/increamented'})
console.log(store.getStore())
//{value:1}

Selectors:

Selector函数可以从store状态树中提取指定的片段,随着应用变大,遇到不同应用程序的不同部分需要读取相同数据,selector可以避免重复这样的状态逻辑

1
2
3
4
const selectCounterValue=state=>state.value
const currentValue = selectCounterValue(store.getState())
console.log(currentValue)
//2

核心概念:

单一数据源:应用程序的全局状态作为对象存储在单个 store 中。任何给定的数据片段都应仅存在于一个位置,而不是在许多位置重复。

state只读

更改状态的唯一方法是 dispatch 一个 action,这是一个描述所发生情况的对象。

这样,UI 就不会意外覆盖数据,并且更容易跟踪发生状态更新的原因。由于 actions 是普通的 JS 对象,因此可以记录、序列化、存储这些操作,并在以后重放这些操作以进行调试或测试。

使用reducer纯函数进行更改:

Reducers 是纯函数,它们采用旧 state 和 action,并返回新 state。

redux数据流:

单向数据流:

root reducer函数创建Redux store=>store调用一次root reducer,并将返回值保存为它的初始state=>UI首次渲染时,UI组件访问Redux store的当前state,并将数据渲染为内容,监听store的更新:

应用更新=>dispatch一个action到Redux store=>store用之前的state和当前的action再次运行reducer函数,并将返回值保存为新的state=>store通知所有订阅过的UI,通知store更新=>每个订阅过store数据的UI组件就会检查它们需要的state部分是否被更新=>发现更新,每个组件强制使用新数据渲染,更新网页

明确两个概念:

UI组件:不能使用任何redux的api,只负责页面的呈现,交互

容器组件:负责和redux通信,将结果交给UI组件

  • 创建一个容器组件:靠react-redux的connect函数,connect(mapStateToProps,mapDispatchToProps)(UI组件)
  • mapStateToProps:映射状态:返回值时一个对象
  • mapDispatchToProps:映射操作状态的方法,返回值是一个对象
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
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
case 'SHOW_ALL':
default:
return todos
}
}

const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}

const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}

const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)

export default VisibleTodoList
  • 容器组件中的store是靠props传进去,而不是在容器组件中直接引入

优化:

  • 容器组件和UI组件整合为一个文件
  • 不用给容器组件传递store,给包裹一个即可
  • 使用react-redux后不用自己检测redux状态的变化,容器组件自己完成这个工作
  • mapDispatchToProps写成一个对象
1
2
3
{
onTodoClick:toggleTodo
}

总结:一个组件与redux打交道步骤:

  • 定义UI组件不暴露
  • 引入connect生成一个容器组件:connect(state=>{key:value}),{key:xxxAction})(UI组件)
  • 在UI组件中通过this.props.xxx读取和操作状态

todoList例子:

https://www.redux.org.cn/docs/basics/ExampleTodoList.html