当使用 redux-toolkit
、redux-actions
、reselect
和 Hooks 时,下面是一个例子,演示如何在 React 中使用它们来创建一个完整的 Redux 工作流。本例子创建一个 TODO 应用,其中包含一个 todos
state,用于存储待办事项。
1. 安装相关依赖
安装 redux
、react-redux
、redux-toolkit
、redux-actions
、reselect
:
npm install --save redux react-redux @reduxjs/toolkit redux-actions reselect
2. 创建 Redux Store
在 src
目录下创建一个 store.js
文件,并使用 redux-toolkit
创建 Redux Store。
import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './todosSlice';
const store = configureStore({
reducer: {
todos: todosReducer,
},
});
export default store;
上述代码使用 configureStore
函数创建了一个 Redux Store,并将 todosReducer
添加到了 Store 中。
3. 创建 Redux Reducer
在 src
目录下创建一个 todosSlice.js
文件,并使用 redux-toolkit
创建 Redux Reducer。
import { createSlice } from '@reduxjs/toolkit';
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addTodo: (state, action) => {
const { id, text } = action.payload;
state.push({ id, text, completed: false });
},
toggleTodo: (state, action) => {
const todo = state.find(todo => todo.id === action.payload);
todo.completed = !todo.completed;
},
deleteTodo: (state, action) => {
return state.filter(todo => todo.id !== action.payload);
},
},
});
export const { addTodo, toggleTodo, deleteTodo } = todosSlice.actions;
export default todosSlice.reducer;
上述代码使用 createSlice
函数创建了一个 Redux Reducer,并包含了三个 actions:addTodo
、toggleTodo
和 deleteTodo
。每个 action 都会返回一个新的 state,而不会直接修改原始 state。
4. 创建 Redux Selectors
在 src
目录下创建一个 selectors.js
文件,并使用 reselect
创建 Redux Selectors。
import { createSelector } from 'reselect';
const getTodos = state => state.todos;
export const getCompletedTodos = createSelector(
[getTodos],
todos => todos.filter(todo => todo.completed)
);
export const getIncompleteTodos = createSelector(
[getTodos],
todos => todos.filter(todo => !todo.completed)
);
上述代码使用 createSelector
函数创建了两个 Redux Selectors:getCompletedTodos
和 getIncompleteTodos
。每个 selector 都将 getTodos
selector 的结果作为参数,并返回一个新的值。
5. 创建 Redux Actions
在 src
目录下创建一个 actions.js
文件,并使用 redux-actions
创建 Redux Actions。
import { createAction } from 'redux-actions';
export const addTodo = createAction('ADD_TODO');
export const toggleTodo = createAction('TOGGLE_TODO');
export const deleteTodo = createAction('DELETE_TODO');
上述代码使用 createAction
函数创建了三个 Redux Actions:addTodo
、toggleTodo
和 deleteTodo
。这些 actions 会自动创建一个 action creator,并生成一个 type 常量,该常量用于在 reducer 中处理 actions。
6. 创建组件
在 src
目录下创建一个 TodoList.js
文件,并编写组件代码。
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addTodo, toggleTodo, deleteTodo } from './actions';
import { getCompletedTodos, getIncompleteTodos } from './selectors';
function TodoList() {
const dispatch = useDispatch();
const completedTodos = useSelector(getCompletedTodos);
const incompleteTodos = useSelector(getIncompleteTodos);
const handleAddTodo = (e) => {
e.preventDefault();
const text = e.target.elements.todo.value;
dispatch(addTodo({
id: Date.now(),
text,
}));
e.target.reset();
};
const handleToggleTodo = (id) => {
dispatch(toggleTodo(id));
};
const handleDeleteTodo = (id) => {
dispatch(deleteTodo(id));
};
return (
<div>
<h1>Todo List</h1>
<form onSubmit={handleAddTodo}>
<input type="text" name="todo" placeholder="Add Todo" />
<button type="submit">Add</button>
</form>
<h2>Incomplete</h2>
<ul>
{incompleteTodos.map(todo => (
<li key={todo.id}>
<span>{todo.text}</span>
<button onClick={() => handleToggleTodo(todo.id)}>Complete</button>
<button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
<h2>Completed</h2>
<ul>
{completedTodos.map(todo => (
<li key={todo.id}>
<span>{todo.text}</span>
<button onClick={() => handleToggleTodo(todo.id)}>Incomplete</button>
<button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default TodoList;
上述代码创建了一个 TodoList
组件,该组件使用了 useDispatch
和 useSelector
Hooks 来与 Redux Store 进行交互。该组件中包含了一个表单,用于添加新的待办事项,并展示了两个列表:未完成的待办事项和已完成的待办事项。每个待办事项都包含了两个按钮:一个用于将待办事项标记为已完成,一个用于将待办事项删除。
最后,在 App.js
文件中使用 TodoList
组件:
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import TodoList from './TodoList';
function App() {
return (
<Provider store={store}>
<TodoList />
</Provider>
);
}
export default App;
上述代码使用 Provider
组件将 Redux Store 传递给 TodoList
组件,使其可以与 Redux Store 进行交互。