ReactJS - 使用 Flux
ReactJS - 使用 Redux Toolkit 进行状态管理
Section titled “ReactJS - 使用 Redux Toolkit 进行状态管理”虽然 Flux 是一种模式,但 Redux 是一个帮助实现它的流行库。Redux Toolkit 极大地简化了现代 Redux 开发,现在它是推荐的方法。本教程将指导你使用 React 和 Redux Toolkit 设置一个简单的 Todo 应用。
第一步 - 安装 Redux Toolkit 和 React-Redux
Section titled “第一步 - 安装 Redux Toolkit 和 React-Redux”在你的 React 项目根目录下打开终端或命令提示符,然后运行:
npm install @reduxjs/toolkit react-redux或者如果你正在使用 Yarn:
yarn add @reduxjs/toolkit react-redux第二步 - 创建项目结构
Section titled “第二步 - 创建项目结构”使用 Redux Toolkit 的常见做法是按‘功能’(features)或‘切片’(slices)组织状态逻辑。对于我们的 Todo 应用,我们将在 src 目录内创建一个 features 目录。
你的 src 文件夹结构可能看起来像这样:
src/├── app/│ └── store.js # Redux store configuration├── features/│ └── todos/│ ├── todosSlice.js # Reducer and actions for todos│ └── Todos.jsx # React component for todos├── App.js # Main application component└── index.js # Entry point, renders App第三步 - 定义 Redux Slice (todosSlice.js)
Section titled “第三步 - 定义 Redux Slice (todosSlice.js)”一个‘Slice’(切片)是单个功能相关的 Redux Reducer 逻辑和 Action 的集合。Redux Toolkit 的 createSlice 函数会自动生成 Action Creator 和 Action 类型。
src/features/todos/todosSlice.js
Section titled “src/features/todos/todosSlice.js”import { createSlice } from '@reduxjs/toolkit';
let nextTodoId = 0;
const todosSlice = createSlice({ name: 'todos', initialState: [], reducers: { addTodo: { reducer(state, action) { state.push(action.payload); // Immer handles immutability here }, prepare(text) { return { payload: { id: nextTodoId++, text, completed: false } }; } }, toggleTodo(state, action) { const todo = state.find(todo => todo.id === action.payload); if (todo) { todo.completed = !todo.completed; } } }});
export const { addTodo, toggleTodo } = todosSlice.actions;export default todosSlice.reducer;要点:
createSlice接收一个名称、一个初始状态和一个 Reducer 函数对象。- 借助 Redux Toolkit 内部运行的 Immer,Reducer 函数可以直接‘修改’(mutate)状态。
addTodo中的prepare回调允许自定义 Action 的有效载荷(payload),这里我们生成一个唯一的 ID。- Action Creator(
addTodo、toggleTodo)会自动生成并导出。
第四步 - 配置 Redux Store (store.js)
Section titled “第四步 - 配置 Redux Store (store.js)”Redux Toolkit 的 configureStore 简化了 Store 的设置。
src/app/store.js
Section titled “src/app/store.js”import { configureStore } from '@reduxjs/toolkit';import todosReducer from '../features/todos/todosSlice';
export const store = configureStore({ reducer: { todos: todosReducer, // other reducers can be added here },});第五步 - 将 Store 提供给 React (index.js)
Section titled “第五步 - 将 Store 提供给 React (index.js)”使用来自 react-redux 的 <Provider> 组件包裹你的根应用组件,以便让 Store 对所有组件可用。
src/index.js
Section titled “src/index.js”import React from 'react';import ReactDOM from 'react-dom/client';import { Provider } from 'react-redux';import { store } from './app/store';import App from './App';import './index.css'; // Assuming you have some basic styling
const root = ReactDOM.createRoot(document.getElementById('root'));root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>);第六步 - 在组件中使用 Redux 状态和 Action (Todos.jsx 和 App.js)
Section titled “第六步 - 在组件中使用 Redux 状态和 Action (Todos.jsx 和 App.js)”我们将使用 useSelector Hook 从 Store 中读取数据,并使用 useDispatch 来调度(dispatch)Action。
src/features/todos/Todos.jsx
Section titled “src/features/todos/Todos.jsx”import React, { useState, useRef } from 'react';import { useSelector, useDispatch } from 'react-redux';import { addTodo, toggleTodo } from './todosSlice';
function Todos() { const todos = useSelector(state => state.todos); const dispatch = useDispatch(); const [text, setText] = useState(''); const inputRef = useRef(null);
const handleAddTodo = (e) => { e.preventDefault(); if (text.trim()) { dispatch(addTodo(text.trim())); setText(''); inputRef.current.focus(); } };
return ( <div> <form onSubmit={handleAddTodo}> <input type="text" value={text} onChange={(e) => setText(e.target.value)} ref={inputRef} placeholder="What needs to be done?" /> <button type="submit">Add Todo</button> </form> <ul> {todos.map(todo => ( <li key={todo.id} onClick={() => dispatch(toggleTodo(todo.id))} style={{ textDecoration: todo.completed ? 'line-through' : 'none', cursor: 'pointer' }} > {todo.text} </li> ))} </ul> </div> );}
export default Todos;现在,我们将 Todos 组件集成到 App.js 中。
src/App.js
Section titled “src/App.js”import React from 'react';import Todos from './features/todos/Todos';import './App.css'; // Assuming you have some basic styling
function App() { return ( <div className="App"> <header className="App-header"> <h1>Todo List with Redux Toolkit</h1> </header> <main> <Todos /> </main> </div> );}
export default App;通过这些步骤,你就拥有了一个使用 React 和 Redux Toolkit 构建的正常工作的 Todo 应用。你可以添加新的待办事项并切换它们的完成状态。这展示了使用 Redux 的现代、简化的方式。
常见陷阱与进一步学习:
- 忘记将
App包裹在<Provider>中。 - 使用
useSelector选择状态时出错(确保你的state.featureName与 Store 配置匹配)。 - 对于更复杂的应用,可以探索使用
createAsyncThunk和 Redux Thunk 等中间件(Redux Toolkit 默认包含)处理异步逻辑。 - 参考 Redux Toolkit 官方文档了解高级模式:https://redux-toolkit.js.org/