Redux 已死:Redux 工具包万岁
在本文中,我们来了解一下 Redux Toolkit,或者用开发团队的话来说,“官方的、自以为是的、功能齐全的高效 Redux 开发工具集”。
Redux 是什么以及它是如何工作的
大多数 Web 开发者可能都听说过 Redux,一个流行的状态管理库。它于 2015 年首次进入前端世界,由 Dan Abramov 和 Andrew Clark 构建,是革命性的状态管理解决方案。
在 React、Angular 或 Vue 等前端框架中,每个组件内部都管理着自己的状态。随着应用变得越来越复杂,跨多个组件管理状态变得繁琐而困难。Redux 正是解决这个问题的解决方案。
Redux 的工作原理是提供一个集中式的“store”,用于保存应用内的所有状态。应用中的每个组件都可以访问这个 store,而无需在组件树中传递 props。
图片来自codecentric
Redux 流程
典型的 Redux 流程如下:
- 用户与视图交互以触发状态更新
- 当需要更新状态时,View 会发出一个动作
- Reducer 从调度器接收 action,并根据 action 描述的内容更新 Store 中的状态
- View 订阅了 Store 来监听状态变化。这些变化通过订阅方法通知 View,View 会相应地更新 UI。
图片来自ESRI
Redux 流程由三个主要组件组成:Action、Reducers 和 Store。理解这些组件之间的关系对于理解 Redux 的工作原理至关重要。
动作是具有必需type
属性的 JavaScript 对象,并且可以在需要时包含自定义属性。它们仅用于描述状态发生了什么,并不负责更改状态。以下是一些动作示例:
//action to add a todo item
{ type: 'ADD_TODO', text: 'This is a new todo' }
//action that pass a login payload
{ type: 'LOGIN', payload: { username: 'foo', password: 'bar' }}
动作type
的 只是一个描述动作的字符串,添加的属性是更新状态所需的信息。动作通过store.dispatch(action)
方法调度,然后由 Reducer 处理状态的更新。
Reducer是纯函数,它接收状态的当前值,按照 Action 的指示对其进行操作,然后输出状态的新值。Reducer 负责更改状态的值。以下是 Reducer 函数的一个简单示例:
//takes in the current state and action
//updates the value based on the action's type
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'INCREASE':
return { value: state.value + 1 }
case 'DECREASE':
return { value: state.value - 1 }
default:
return state
}
}
最后,状态将在 Store 中更新。Store是管理所有状态的地方。只需一行代码即可创建:
const store = createStore(myComponent);
组件必须订阅 Store 来监听状态更新,以便在 UI 中正确呈现状态。该store.subscribe()
方法添加了一个更改监听器,每当 action 被调度时,该监听器都会被调用。
为什么选择 Redux Toolkit
至此,我们明白了为什么 Redux 成为状态管理的热门选择。它的模式使得状态可预测,因为 Reducer 是纯函数,这意味着传递的相同状态和 Action 总是会产生相同的输出。
由于 Redux 流程中每个部分的行为和工作方式都经过了严格的组织,因此它也易于维护和扩展。此外,Redux 还带来了许多其他好处,例如高效的测试、轻松的调试和更佳的性能。
然而,这个灵活且高级的状态管理库面临着一些挑战:
- 需要太多代码来将 Store 配置为优化级别/最佳实践
- 过多的样板代码会使代码不够干净和高效。
- 构建可扩展应用程序需要安装太多软件包
- 在大型应用程序中编写操作和减速器变得更加复杂和繁琐
为了应对这些挑战,Redux 团队推出了 Redux Toolkit,这是官方推荐的编写 Redux 逻辑的方法。它旨在通过将 Redux Core 与他们认为构建 Redux 应用所必需的软件包相结合,来加快 Redux 的开发速度。它是 Redux 的衍生产品,为 Redux 初学者或想要简洁、快速、干净的 Redux 代码的开发人员提供了许多最佳实践配置。
因此,让我们开始使用 Redux Toolkit 并使用新的 React 应用程序进行设置。
Redux Toolkit 入门
步骤 1:安装软件包
要开始使用 Redux Toolkit 和 React-Redux 包,您可以在现有的 React 应用上运行以下命令:
npm install @reduxjs/toolkit react-redux
或者,通过 Create React App 安装:
npx create-react-app my-app --template redux
步骤2:创建并初始化商店
现在让我们创建一个 store 来保存我们的状态。我们可以在文件夹store.js
中创建一个文件src
,并在其中添加以下代码:
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {} //add reducers here
})
此处的 替换了Redux 中的configureStore
原有。与 不同,Redux Toolkit 中的 不仅可以创建 store,还可以接受 reducer 函数作为参数,并自动设置 Redux DevTools Extension 以便于调试。createStore
createStore
configureStore
步骤 3:在 React 应用中提供 Store
一旦我们的商店创建完成,我们就需要让 React 应用中的每个组件都能够访问它。我们可以使用Provider
之前react-redux
安装的包中的 来实现这一点。
在我们的index.js
文件中,我们像这样导入Provider
和我们的store.js
:
import store from './store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
步骤 4:编写 Reducer 和 Action
我们现在可以为我们的 Redux 存储编写一些 reducer 函数和操作。
在传统的 Redux 中,我们通常会分别编写 Reducer 和 Action。例如,一个计数器应用的简单 Reducer 和 Action 在传统的 Redux 中会像这样编写:
行动
// actions/index.js
export const Increase = () => ({
type: 'INCREASE'
})
export const Decrease = () => ({
type: 'DECREASE'
})
Reducers
// reducers/index.js
export default (state = 0, action) => {
switch (action.type) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
default:
return state
}
}
使用 Redux Toolkit,我们可以通过使用 使代码更加简洁。在应用程序的文件夹中createSlice
创建一个文件。Reducer 和 Action 都可以像这样写在切片下:counterSlice.js
src
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increase: state => {
state.value += 1
},
decrease: state => {
state.value -= 1
}
}
})
// each case under reducers becomes an action
export const { increase, decrease } = counterSlice.actions
export default counterSlice.reducer
从上面的代码可以看出,在 Redux Toolkit 中定义 Reducer 和 Action 变得更加简洁快捷。不再需要使用 switch 语句来管理 Action 及其对应的 Reducer。
你可能注意到的另一件事是,我们现在似乎直接在 Reducer 函数中修改了状态的值,而不是返回一个新值来更新状态。这实际上是因为 Redux Toolkit 使用了 Immer 库,它允许在 Reducer 中编写“修改”逻辑。
有关 Immer 如何工作的更多信息,请访问此处的文档。
步骤5:将 Reducer 导入到 Store
我们已经从 中导出了 Reducer 和 Actions counterSlice.js
。接下来,让我们将 Reducer 导入到 中store.js
。
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '.counterSlice' //import our reducer from step 4
export default configureStore({
reducer: {
counter: counterReducer //add our reducer from step 4
}
})
步骤 6:从 UI 调度操作
正如我们之前所了解的,我们的 View 会触发一个 action 来分发,以更新状态。在 Redux 中,我们使用store.dispatch(action)
分发 action。
相反,让我们使用 React-Redux 来使用useDispatch
钩子来分派动作并useSelector
从存储中读取数据。
在我们的文件夹中创建一个Counter.js
文件src
来表示我们的 Counter 组件。在这个文件中,我们将从 React-Redux 导入我们的useDispatch
和useSelector
hooks。我们还将从 导入我们的 action counterSlice.js
。
import { useSelector, useDispatch } from 'react-redux'
import { decrease, increase } from './counterSlice'
然后,我们的 Counter 函数将初始化我们的 2 个钩子并返回dispatch(action)
在点击时触发的 UI 元素。
export function Counter() {
const count = useSelector(state => state.counter.value)
// in our slice, we provided the name property as 'counter'
// and the initialState with a 'value' property
// thus to read our data, we need useSelector to return the state.counter.value
const dispatch = useDispatch()
// gets the dispatch function to dispatch our actions
return (
<div>
<button onClick={() => dispatch(increase())}>
Increase
</button>
<p>{count}<p>
<button onClick={() => dispatch(decrease())}>
Decrease
</button>
</div>
)
}
开源会话重播
在生产环境中调试Web 应用程序可能既困难又耗时。OpenReplay是 FullStory、LogRocket 和 Hotjar 的开源替代方案。它允许您监控和重放用户的所有操作,并显示您的应用在遇到每个问题时的表现。
这就像打开浏览器的检查器,同时监视用户的行为。OpenReplay
是目前唯一可用的开源替代方案。
对于现代前端团队来说,快乐调试 -开始免费监控您的网络应用程序。
结论
Redux Toolkit 对于初学者和想要减少 Redux 样板代码的开发者来说都是一个不错的选择。它使我们能够编写更简洁、更易读的代码,同时保持 Redux 的流程和模式。
感谢您的阅读。希望本文能帮助您理解 Redux 并在应用程序中使用 Redux Toolkit。谢谢!
文章来源:https://dev.to/asayerio_techblog/redux-is-dead-long-live-redux-toolkit-db8