目录
入门
Redux 是一个使用叫做“action”的事件来管理和更新应用状态的模式和工具库 它以集中式Store(centralized store)的方式对整个应用中使用的状态进行集中管理,其规则确保状态只能以可预测的方式更新。
我们应该什么时候使用?
- 在应用的大量地方,都存在大量的状态
- 应用状态会随着时间的推移而频繁更新
- 更新该状态的逻辑可能很复杂
- 中型和大型代码量的应用,很多人协同开发
Redux库和工具
Redux 是一个小型的独立 JS 库。 但是,它通常与其他几个包一起使用:
React-Redux
Redux可以与任何UI框架集成,最常用于React。React-Redux是我们的官方软件包,它允许您的React组件通过读取状态片段和调度操作来更新存储,从而与Redux存储交互。
Redux Toolkit
Redux Toolkit是我们推荐的编写 Redux 逻辑的方法。 它包含我们认为对于构建 Redux 应用程序必不可少的包和函数。 Redux Toolkit 构建在我们建议的最佳实践中,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序变得更加容易。
Redux DevTools 扩展
Redux DevTools扩展程序可以显示 Redux 存储中状态随时间变化的历史记录。这允许您有效地调试应用程序,包括使用强大的技术,如“时间旅行调试”。
demo练习准备工作:
安装Redux Toolkit
# NPM
npm install @reduxjs/toolkit
# Yarn
yarn add @reduxjs/toolkit
创建一个React Redux应用,使用 官方 Redux+JS 模版 它基于Create React App,它利用了Redux Toolkit和Redux与React组件的集成。
npx create-react-app my-app --template redux
安装Redux
# NPM
npm install redux
# Yarn
yarn add redux
配套工具
npm install react-redux
npm install --save-dev redux-devtools
基础示例
应用的整体全局状态以对象树的方式存放于单个 store。 唯一改变状态树(state tree)的方法是创建 action,一个描述发生了什么的对象,并将其 dispatch 给 store。要指定状态树如何响应 action 来进行更新,你可以编写纯 reducer 函数,这些函数根据旧 state 和 action 来计算新 state。
import { createStore } from 'redux'
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
let store = createStore(counterReducer)
store.subscribe(() => console.log(store.getState()))
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}
Redux Toolkit示例
Redux Toolkit 简化了编写 Redux 逻辑和设置 store 的过程。 使用 Redux Toolkit,相同的逻辑如下所示:
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
state.value += 1
}
}
})
export const { incremented, decremented } = counterSlice.actions
const store = configureStore({
reducer: counterSlice.reducer
})
// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))
store.dispatch(incremented())
// {value: 1}
Redux术语和概念
- state:驱动应用的真实数据源头
- view:基于当前状态的 UI 声明性描述
- actions:根据用户输入在应用程序中发生的事件,并触发状态更新
redux是单向数据流
不可变性Immutability
"Mutable" 意为 "可改变的",而 "immutable 意为永不可改变。
JavaScript 的对象(object)和数组(array)默认都是 mutable 的。如果我创建一个对象,我可以更改其字段的内容。如果我创建一个数组,我也可以更改内容:
const obj = { a: 1, b: 2 }
// 对外仍然还是那个对象,但它的内容已经变了
obj.b = 3
const arr = ['a', 'b']
// 同样的,数组的内容改变了
arr.push('c')
arr[1] = 'd'
这就是 改变 对象或数组的例子。内存中还是原来对象或数组的引用,但里面的内容变化了。
如果想要不可变的方式来更新,代码必需先复制原来的 object/array,然后更新它的复制体。
可以使用如下或其它方式
const obj1 = { name: '冰墩墩', info: {age: 18} };
// 方式1通过扩展运算符
const obj2 = {
...obj1, // obj1的备份
info: {
...obj1.info, // ojb1.info的备份
age: 16, // 覆盖age
}
}
// 方式2通过Object.assign
const obj3 = Object.assign({}, obj1, {name: '冰墩墩', info: {age: 22}});
术语
Action是一个具有 type
字段的普通 JavaScript 对象。你可以将 action 视为描述应用程序中发生了什么的事件.
type
字段是一个字符串,给这个 action 一个描述性的名字,比如"todos/todoAdded"
。我们通常把那个类型的字符串写成“域/事件名称”,其中第一部分是这个 action 所属的特征或类别,第二部分是发生的具体事情。
action 对象可以有其他字段,其中包含有关发生的事情的附加信息。按照惯例,我们将该信息放在名为 payload
的字段中。
一个典型的 action 对象可能如下所示:
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
Reducer
reducer 是一个函数,接收当前的 state
和一个 action
对象,必要时决定如何更新状态,并返回新状态。函数签名是:(state, action) => newState
。
Reducer 必需符合以下规则:
- 仅使用
state
和action
参数计算新的状态值 - 禁止直接修改
state
。必须通过复制现有的state
并对复制的值进行更改的方式来做 不可变更新(immutable updates)。 - 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码
例
const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
// 检查 reducer 是否关心这个 action
if (action.type === 'counter/increment') {
// 如果是,复制 `state`
return {
...state,