我们在学习和使用React做项目的时候,肯定离不开Redux的使用。那么 “Redux” 是什么呢?。它有什么作用?它帮助我解决什么问题?我为什么要使用它?搞懂这些能让我们更好的理解和使用Redux。
Redux 是什么?
Redux是一个用于JavaScript应用程序状态管理的开源库。它可以帮助你更好地组织和管理应用程序的状态,并提供可预测性和可维护性。
为什么需要使用Redux?(现实面临的问题)
在大型JavaScript应用程序中,随着应用程序变得复杂,状态管理变得困难。我们常见的React框架。它就存在着许多常见的问题例如
ac
- 共享状态困难:多个组件需要访问和共享同一个状态。当状态分散在应用程序的不同部分时,跟踪和管理状态变得困难,容易引发bug。a
- 状态更新难异常:状态可能被多个组件同时修改,导致状态的一致性问题。在没有明确规定的情况下,状态变更可能不可预测,难以维护和调试。
- 组件通信困难:组件之间需要进行复杂的通信和协调。在没有统一的机制来管理共享状态时,组件之间的通信变得困难,代码变得冗杂。
而我们的Redux
就能帮助我们很好的解决这些问题。那么你可能有会问了为什么偏偏是Redux呢?为什么不能是
MobX
、Zustand
或者是Recoil
呢?
Redux的优点
-
高度的可预测性:Redux的状态管理遵循严格的单向数据流,所有的状态变更都是通过分发操作来进行的。这种一致的数据流模式使得状态变更变得可预测,容易理解和调试。
-
强大的工具生态系统:Redux拥有丰富的工具和插件生态系统,包括Redux DevTools等。这些工具提供了强大的调试和开发工具,使得在开发过程中能够更好地理解应用程序的状态变化,进行时间旅行调试等。
-
可扩展性和灵活性:Redux通过中间件机制提供了灵活的扩展能力。你可以使用中间件来处理异步操作、日志记录、路由等复杂逻辑,而无需修改核心的状态管理逻辑。这种可扩展性使得Redux适用于各种规模和复杂度的应用程序。
-
状态的集中管理:Redux使用单一不可变状态树来管理整个应用程序的状态。这种集中化的状态管理使得状态变更更容易追踪和调试,避免了状态分散和不一致的问题。
-
拥有成熟的社区和文档支持:Redux拥有庞大的社区和成熟的文档支持,你可以轻松找到大量的教程、示例和问题解答。这使得学习和使用Redux变得更加容易,有助于解决开发中的问题。
-
组件解耦和可复用性:Redux将应用程序的状态从组件中解耦出来,通过容器组件和连接器(connectors)来连接组件和状态。这种解耦使得组件更加独立和可复用,减少了组件之间的直接依赖关系。你可以在任何地方使用相同的状态,并且组件可以专注于渲染和响应用户操作,而不必关心状态的细节。
我什么时候应该使用 Redux呢?
Redux 可帮助你处理共享状态的管理,但与任何工具一样,它也需要权衡利弊。使用 Redux 需要添加了一些额外代码,并要求你遵循某些限制。这是短期和长期生产力之间的权衡。
在以下情况下我们就应该使用 Redux:
- 应用中有很多 state 在多个组件中需要使用
- 应用 state 会随着时间的推移而频繁更新
- 更新 state 的逻辑很复杂
- 中型和大型代码量的应用,很多人协同开发
并非所有应用程序都需要 Redux。 花一些时间思考你正在构建的应用程序类型,并决定哪些工具最能帮助解决你正在处理的问题。
Reducer
在Redux中,
Reducer
是一个纯函数,用于处理状态的更新。它接收当前的状态(previous state)和一个动作(action对象)作为参数,并返回一个新的状态(new state)。你可以将 reducer 视为一个事件监听器它根据动作的类型来决定如何更新状态。
使用规则
- 禁止直接修改 state。必须通过复制现有的
state
并对复制的值进行更改的方式来做 不可变更新(immutable updates) 。这种方式可以确保Redux存储中的先前状态保持不变,以便进行状态的时间旅行和调试。 - 纯函数:Reducer必须是纯函数。不能产生有副作用,不应该修改传入的参数,也不应该执行异步操作。Reducer的输出应仅依赖于输入的先前状态和动作,而不受其他外部因素的影响。
Store
在Redux中,
Store
是一个包含应用程序状态的对象。它是整个Redux应用程序的核心部分,用于存储、更新和访问应用程序的状态。store 是通过传入一个 reducer 来创建的,并且有一个名为 getState 的方法,它返回当前状态值
使用规则
- Store是唯一的:应用程序应该只有一个唯一的Store。
- 使用
store.getState()
方法来获取当前的状态对象 - 使用
store.dispatch(action)
方法来分发动作 - 使用
store.subscribe(listener)
方法来注册一个监听器
Action
在Redux中,Action是一个包含
type
字段的普通JavaScript对象,用于描述应用程序中发生的动作。它是触发状态更新的唯一来源。
Action结构
Action对象通常具有以下结构:
{
type: 'ACTION\_TYPE',
payload: // 可选,用于携带数据或其他相关信息的字段
}
-
type字段是Action的类型,用于标识要执行的操作。它通常是一个字符串常量,表示应用程序中的某个动作。例如,type: 'INCREMENT’表示执行一个增加的动作。
-
payload字段是可选的,用于携带数据或其他相关信息。它可以是任何JavaScript值,如对象、数组、字符串、数字等。如果有需要,可以使用payload字段来传递需要用于状态更新的数据
Dispatch
在Redux中,dispatch是一个用于分发(触发)Action的方法。它是Redux Store对象的一个方法。
使用store.dispatch(action)语法,我们可以将一个Action分发到Redux的Store中,从而触发相应的状态更新。
Selector
在Redux中,Selector是一个函数,用于从应用程序的状态中获取特定的数据。它可以帮助我们在应用程序的不同部分中选择和提取所需的数据,而不需要直接访问整个状态对象。
代码示例:
const selectCounterValue = state => state.value
const currentValue = selectCounterValue(store.getState())
console.log(currentValue)
-
在这个示例中,selectCounterValue是一个简单的Selector函数,它从Redux的状态中选择并返回value字段。
-
首先,我们使用store.getState()方法获取当前的Redux状态。然后,我们将该状态作为参数传递给selectCounterValue函数,以获取value字段的值。
-
最后,我们将得到的currentValue打印到控制台。
使用方法
-
定义初始状态值:首先,你需要定义一个初始状态对象。它表示应用程序的初始状态。例如:
const initialState = { count: 0 };
-
创建Reducer:创建一个Reducer函数来处理状态的更新。Reducer函数是一个纯函数,接收先前的状态和动作对象作为参数,并返回一个新的状态对象。根据动作的类型,Reducer决定如何更新状态。例如:
const counterReducer = (state = initialState, action) => { switch (action.type) { case 'INCREMENT': return { ...state, count: state.count + 1 }; case 'DECREMENT': return { ...state, count: state.count - 1 }; default: return state; } };
-
创建Store:使用Redux提供的
createStore
函数来创建一个Store。将Reducer作为参数传递给createStore
函数,这样Store就能够使用Reducer来处理状态的更新。例如:import { createStore } from 'redux'; const store = createStore(counterReducer);
-
访问状态:通过调用
store.getState()
方法,你可以获取当前的状态对象。例如:const currentState = store.getState();
-
分发动作:要更新状态,你需要分发一个动作。动作是一个包含
type
字段的普通JavaScript对象,用于描述要执行的操作。使用store.dispatch(action)
方法来分发动作并触发状态的更新。例如:const incrementAction = { type: 'INCREMENT' }; store.dispatch(incrementAction);
-
监听状态变化:如果你希望在状态发生变化时执行一些操作,可以使用
store.subscribe(listener)
方法来订阅状态的变化。每当状态更新时,监听器函数将被调用。例如:const listener = () => { const currentState = store.getState(); // 处理状态变化 }; store.subscribe(listener);
通过上述步骤,你就可以在Redux中使用Reducer来管理和更新状态了。Reducer定义了如何根据动作类型更新状态,Store负责存储状态并提供相关的方法来访问和更新状态。
Redux 的数据流
早些时候,我们谈到了“单向数据流”,它描述了更新应用程序的以下步骤序列:
- State 描述了应用程序在特定时间点的状况
- 基于 state 来渲染视图
- 当发生某些事情时(例如用户单击按钮),state 会根据发生的事情进行更新
- 基于新的 state 重新渲染视图
具体来说,对于 Redux,我们可以将这些步骤分解为更详细的内容:
-
初始启动:
- 使用最顶层的 root reducer 函数创建 Redux store
- store 调用一次 root reducer,并将返回值保存为它的初始
state
- 当视图 首次渲染时,视图组件访问 Redux store 的当前 state,并使用该数据来决定要呈现的内容。同时监听 store 的更新,以便他们可以知道 state 是否已更改。
-
更新环节:
- 应用程序中发生了某些事情,例如用户单击按钮
- dispatch 一个 action 到 Redux store,例如
dispatch({type: 'counter/increment'})
- store 用之前的
state
和当前的action
再次运行 reducer 函数,并将返回值保存为新的state
- store 通知所有订阅过的视图,通知它们 store 发生更新
- 每个订阅过 store 数据的视图 组件都会检查它们需要的 state 部分是否被更新。
- 发现数据被更新的每个组件都强制使用新数据重新渲染,紧接着更新网页
动画的方式来表达数据流更新: