Redux 提供的模式和工具使你更容易理解应用程序中的状态何时、何地、为什么、state 如何被更新,以及当这些更改发生时你的应用程序逻辑将如何表现**. Redux 指导你编写可预测和可测试的代码,这有助于你确信你的应用程序将按预期工作。
不止是Redux,所有状态管理工具的目标都是如此。
Redux作为Flux的一个变体,在Flux单向数据流的基础上又多增加了几条准则:
- 唯一数据源(Single Source of Truth);
- 保持状态只读(State is read-only);
- 数据改变只能通过纯函数完成
Store
通过configureStore创建一个store,传入的options的类型中,有必传的reducer属性,有初始化state属性preloadedState
export declare function configureStore(options: ConfigureStoreOptions<S, A, M, E>): EnhancedStore<S, A, M, E>;
export interface ConfigureStoreOptions{
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
preloadedState?: PreloadedState<CombinedState<NoInfer<S>>>;
}
export const store = configureStore({
reducer: {
counter: counterReducer
}
});
name为counter的state,对应counterReducer来更新
返回的store类型如下,有几个比较重要的方法:
export interface Store {
dispatch: Dispatch<A>;
getState(): S & StateExt;
subscribe(listener: ListenerCallback): Unsubscribe;
}
dispatch方法主要做两件事:
- 内部根据 action 和 state 调用传入的 reducer 拿到新的state
- 循环调用 listener
Action
Redux中的action就是一个简单的object,有唯一的属性type
export type Action<T extends string = string> = {
type: T
}
Redux内部提供了 UnknownAction 和 AnyAction,通常我们也是使用的也是这两个,在type的基础上挂载额外的payload字段,可以看到额外的字段类型是unknow或者any。
export interface UnknownAction extends Action {
// Allows any extra properties to be defined in an action.
[extraProps: string]: unknown
}
export interface AnyAction extends Action {
// Allows any extra properties to be defined in an action.
[extraProps: string]: any
}
一个简单的action定义:
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
Reducer
reducer是一个函数,函数签名是:(state, action) => newState
Reducer 必需符合以下规则:
- 仅使用 state 和 action 参数计算新的状态值
- 禁止直接修改 state。必须通过复制现有的 state 并对复制的值进行更改的方式来做 不可变更新(immutable updates) 。Redux期望所有状态更新都使用不可变的方式。Redux Toolkit 允许我们写可变的逻辑是因为内部用了 Immer 库,会自动帮我吗处理数据的不可变性。
- 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码
Reducer 函数内部的逻辑通常遵循以下步骤:
-
检查 reducer 是否关心这个 action
- 如果是,则复制 state,使用新值更新 state 副本,然后返回新 state
-
否则,返回原来的 state 不变
Dispatch
Redux store 有一个方法叫 dispatch。更新 state 的唯一方法是调用 store.dispatch() 并传入一个 action 对象
store.dispatch({ type: 'counter/increment' })
dispatch 一个 action 可以形象的理解为 "触发一个事件" 。发生了一些事情,我们希望 store 知道这件事。 Reducer 就像事件监听器一样,当它们收到 action 后,它就会更新 state 作为响应。
当我们有多个组件需要共享和使用相同 state时,可能会变得很复杂,尤其是当这些组件位于应用程序的不同部分时。有时这可以通过 "提升 state" 到父组件来解决,但这并不总是有效。
解决这个问题的一种方法是从组件中提取共享 state,并将其放入组件树之外的一个集中位置。这样,我们的组件树就变成了一个大“view”,任何组件都可以访问 state 或触发 action,无论它们在树中的哪个位置!
通过定义和分离 state 管理中涉及的概念并强制执行维护 view 和 state 之间独立性的规则,代码变得更结构化和易于维护。
这就是 Redux 背后的基本思想:应用中使用集中式的全局状态来管理,并明确更新状态的模式,以便让代码具有可预测性。