Redux 是一个流行的 JavaScript 状态管理库,特别适合管理大型应用中的复杂状态。本文将带你从零开始,一步步构建一个使用 Redux 管理的待办事项应用。
📌 一、什么是 Redux?为什么我们需要它?
想象一下,你正在开发一个 React 应用,里面有多个组件需要共享一些数据,比如用户信息、购物车内容、待办事项等等。
这时候你可能会遇到以下问题:
- 组件之间如何共享数据?
- 数据更新时,如何保证所有相关组件都能同步更新?
- 如果数据更新逻辑变得复杂,该怎么管理?
Redux 就是为了解决这些问题而诞生的。
你可以把它想象成一个中央仓库(Store) ,所有组件都可以从这里获取数据,也可以通知它来修改数据。这样一来,数据就不再是某个组件的“私有财产”,而是整个应用的“公共资源”。
🌟 Redux 的三大核心概念:
- Store(仓库) :保存整个应用的状态。
- Action(动作) :描述发生了什么,比如“添加一个待办事项”。
- Reducer(状态管理函数) :根据动作来更新状态。
二、项目初始化:创建 React 项目并安装 Redux 相关依赖
我们使用 create-react-app 快速搭建项目:
npx create-react-app redux-todo-demo
cd redux-todo-demo
接着安装 Redux 的两个关键依赖:
npm install @reduxjs/toolkit react-redux
📦 安装说明:
@reduxjs/toolkit:这是 Redux 官方推荐的工具包,它简化了 Redux 的使用方式,减少了很多样板代码。react-redux:连接 React 和 Redux 的桥梁,让我们可以在 React 组件中方便地使用 Redux。
🧱 三、创建 Redux 子模块:待办事项模块
在 Redux 中,我们通常会将不同的功能模块化。比如,待办事项可以作为一个独立的模块,便于管理和维护。
✅ 创建文件:src/store/modules/todolistStore.js
import { createSlice } from '@reduxjs/toolkit'
// 使用 createSlice 创建一个切片(子模块)
const todolist = createSlice({
name: 'todolist', // 模块名称,后续作为命名空间使用
initialState: {
list: [] // 初始状态是一个空数组
},
reducers: {
// 添加待办事项
addList: (state, action) => {
state.list.push(action.payload)
},
// 删除指定索引的待办事项
deleteList: (state, action) => {
state.list.splice(action.payload, 1)
}
}
})
// 导出 actions
export const { addList, deleteList } = todolist.actions
// 导出 reducer
export default todolist.reducer
📖 代码解释:
-
createSlice:这是 Redux Toolkit 提供的 API,用于创建一个“切片”(slice),也就是一个独立的状态模块。 -
name:这个模块的名字,后续在状态树中会成为命名空间。 -
initialState:初始状态,我们这里是一个空数组,表示待办事项列表初始为空。 -
reducers:定义状态的更新方法,每个方法接收当前状态和一个 action。addList:添加一个事项到列表中。deleteList:根据索引删除一个事项。
💡 小贴士:Redux Toolkit 允许我们在 reducer 中“直接修改状态”,这是因为它内部使用了 Immer 库来处理不可变更新,不需要我们手动返回新对象。
🏗️ 四、创建总仓库:把模块整合起来
现在我们已经有了一个模块(todolist),接下来需要创建一个总仓库(store),把所有模块都整合进去。
✅ 创建文件:src/store/index.js
import { configureStore } from '@reduxjs/toolkit'
import todolistReducer from './modules/todolistStore'
// 创建并导出总仓库
export default configureStore({
reducer: {
todolist: todolistReducer
}
})
📖 代码解释:
-
configureStore:这是 Redux Toolkit 提供的方法,用来创建一个 Redux 仓库。 -
reducer:在这里注册所有模块的 reducer。todolist是模块名,todolistReducer是我们导出的 reducer。
💡 小贴士:虽然我们这里只有一个模块,但你可以继续添加更多模块,比如用户模块、计数器模块等,只需要在这里注册即可。
🔌 五、在 React 中使用 Redux:连接仓库
为了让整个 React 应用都能访问到 Redux 仓库,我们需要使用 react-redux 提供的 <Provider> 组件。
✅ 修改文件:src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
📖 代码解释:
Provider:这是一个 React 组件,它把 Redux 的 store 传递给整个应用。store:我们之前创建的总仓库,传给Provider后,所有子组件都可以通过useSelector和useDispatch来访问和修改状态。
🧩 六、在组件中使用 Redux:获取和修改状态
现在我们已经创建好了 Redux 仓库,并且定义好了状态(state)和操作方法(actions 和 reducers),接下来就可以在 React 组件中使用这些状态和方法了。
在 Redux 中,我们主要通过两个钩子函数来访问仓库:
useSelector:从仓库中获取状态(state)useDispatch:从仓库中调用操作状态的方法(actions)
下面我们来详细看看如何使用它们。
✅ 示例 1:从仓库中获取状态 —— 显示待办事项列表
javascript
深色版本
import { useSelector } from 'react-redux'
function TodoList() {
// 使用 useSelector 获取 Redux 仓库中的 list 状态
const { list } = useSelector((state) => state.todolist)
return (
<ul>
{list.map((item, index) => (
<li key={index}>
{item}
<DeleteTodo index={index} />
</li>
))}
</ul>
)
}
📌 说明:
useSelector是一个 React 钩子函数,用于从 Redux 的仓库中获取数据。- 我们传入一个函数
(state) => state.todolist,它从整个状态树中提取出我们关心的模块(这里是todolist)。 - 然后我们从这个模块中取出
list,这就是我们保存的待办事项列表。 - 每个事项都渲染成
<li>标签,并在每个事项后面添加一个删除按钮组件<DeleteTodo />。
✅ 示例 2:调用仓库中的方法 —— 添加待办事项
javascript
深色版本
import { useDispatch } from 'react-redux'
import { addList } from '../store/modules/todolistStore'
import { useState } from 'react'
function AddTodo() {
const dispatch = useDispatch()
const [inputValue, setInputValue] = useState('')
const handleAdd = () => {
if (inputValue.trim()) {
dispatch(addList(inputValue))
setInputValue('')
}
}
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="输入待办事项"
/>
<button onClick={handleAdd}>添加</button>
</div>
)
}
📌 说明:
useDispatch是另一个 React 钩子函数,它让我们可以“派发”(dispatch)一个 action。addList是我们之前定义的 action,用于添加一个新的待办事项。- 当用户点击“添加”按钮时,我们就调用
dispatch(addList(inputValue)),把输入框中的内容传入仓库。 - 输入框的值我们使用了 React 的本地状态
useState来管理。
✅ 示例 3:调用仓库中的方法 —— 删除待办事项
javascript
深色版本
import { useDispatch } from 'react-redux'
import { deleteList } from '../store/modules/todolistStore'
function DeleteTodo({ index }) {
const dispatch = useDispatch()
return (
<button onClick={() => dispatch(deleteList(index))}>
删除
</button>
)
}
📌 说明:
deleteList是我们在模块中定义的另一个 action,用于删除指定索引的事项。- 我们通过
dispatch(deleteList(index))把索引值传给仓库。 - 这个组件接收一个
index属性,表示要删除的是第几个事项。
📚 七、TodoList(待办事项)应用
项目实现了以下功能:
✅ 添加新的待办事项
✅ 删除指定事项
✅ 全选/取消全选所有事项
项目地址:giteehttps://gitee.com/dragon-team-123/js_al/tree/master/react/react-redux1/src