React useContext 和 useReducer Hooks。
React useContext 和 useReducer Hooks 的一个简单示例,可在 React 中用作 Redux 的替代品。
我们可以使用 React 内置的 hooks,而不是使用 Redux 进行状态管理。最终,你可以将依赖 Redux 的项目替换或迁移到内置 hooks 中。
useContext 钩子用于创建可在整个组件层次结构中访问的通用数据,而无需手动将 props 传递到每个层级。定义的 Context 将可供所有子组件使用,而无需涉及“props”。React Context 是 React 中一个强大的状态管理功能。React Context 允许您将 props 广播到下面的组件,而无需将 props 传递到每个组件。
useReducer 钩子用于复杂的状态操作和状态转换。... useReducer 是一个 React 钩子函数,它接受一个 reducer 函数和一个初始状态。const [state, dispatch] = useReducer(reducer, initialState);这个钩子函数返回一个包含 2 个值的数组。
为了便于理解,我使用了待办事项列表示例的常见用例。
步骤 1:初始状态和操作
//Initial State and Actions
const initialState = {
todoList: []
};
const actions = {
ADD_TODO_ITEM: "ADD_TODO_ITEM",
REMOVE_TODO_ITEM: "REMOVE_TODO_ITEM",
TOGGLE_COMPLETED: "TOGGLE_COMPLETED"
};
步骤 2:处理 Action 的 Reducer
//Reducer to Handle Actions
const reducer = (state, action) => {
switch (action.type) {
case actions.ADD_TODO_ITEM:
return {
todoList: [
...state.todoList,
{
id: new Date().valueOf(),
label: action.todoItemLabel,
completed: false
}
]
};
case actions.REMOVE_TODO_ITEM: {
const filteredTodoItem = state.todoList.filter(
(todoItem) => todoItem.id !== action.todoItemId
);
return { todoList: filteredTodoItem };
}
case actions.TOGGLE_COMPLETED: {
const updatedTodoList = state.todoList.map((todoItem) =>
todoItem.id === action.todoItemId
? { ...todoItem, completed: !todoItem.completed }
: todoItem
);
return { todoList: updatedTodoList };
}
default:
return state;
}
};
代码细分:我们使用通常的 Switch Case 语句来评估操作。
- 第一种情况 ADD_TODO_ITEM -action 扩展现有列表并使用 id(唯一)、标签(用户输入的值)和已完成标志向列表添加新的待办事项。
- 第二种情况 REMOVE_TODO_ITEM -action 根据 id 过滤出需要删除的待办事项。
- 第三种情况 TOGGLE_COMPLETED - 动作循环遍历所有待办事项并根据 id 切换已完成标志。
步骤 3:创建上下文和提供程序来分派操作。
//Context and Provider
const TodoListContext = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = React.useReducer(reducer, initialState);
const value = {
todoList: state.todoList,
addTodoItem: (todoItemLabel) => {
dispatch({ type: actions.ADD_TODO_ITEM, todoItemLabel });
},
removeTodoItem: (todoItemId) => {
dispatch({ type: actions.REMOVE_TODO_ITEM, todoItemId });
},
markAsCompleted: (todoItemId) => {
dispatch({ type: actions.TOGGLE_COMPLETED, todoItemId });
}
};
return (
<TodoListContext.Provider value={value}>
{children}
</TodoListContext.Provider>
);
};
在这一步中,我们创建 TodoListContext 和一个返回 TodoListContext 的 Provider 的 Provider 函数。
以下是代码的细分。
- 这里我们将 reducer 函数和 initialState 传递给 useReducer hook。这将返回 state 和 dispatch。state 包含 initialState。dispatch 用于触发我们的 action,就像在 redux 中一样。
- 在值对象中,我们有 todoList 状态,以及三个函数 addTodoItem、removeTodoItem 和 markAsCompleted,它们分别触发 ADD_TODO_ITEM、REMOVE_TODO_ITEM 和 TOGGLE_COMPLETED 操作。
- 我们将值对象作为 prop 传递给 TodoListContext 的 Provider,以便我们可以使用 useContext 访问它。
步骤 4:创建将使用 store 的两个组件。AddTodo
和 TodoList
// AddTodo Component with Input field and Add Button
const AddTodo = () => {
const [inputValue, setInputValue] = React.useState("");
const { addTodoItem } = React.useContext(TodoListContext);
return (
<>
<input
type="text"
value={inputValue}
placeholder={"Type and add todo item"}
onChange={(e) => setInputValue(e.target.value)}
/>
<button
onClick={() => {
addTodoItem(inputValue);
setInputValue("");
}}
>
Add
</button>
</>
);
};
在这个AddTodocomponent中,我们使用useContext来订阅我们的TodoListContext并获取addTodoItem调度函数。
//TodoList Component to show the list
const TodoList = () => {
const { todoList, removeTodoItem, markAsCompleted } = React.useContext(
TodoListContext
);
return (
<ul>
{todoList.map((todoItem) => (
<li
className={`todoItem ${todoItem.completed ? "completed" : ""}`}
key={todoItem.id}
onClick={() => markAsCompleted(todoItem.id)}
>
{todoItem.label}
<button
className="delete"
onClick={() => removeTodoItem(todoItem.id)}
>
X
</button>
</li>
))}
</ul>
);
};
在 TodoList 组件中,我们使用 useContext 订阅 TodoListContext 并获取 todoList 状态、removeTodoItem 和 markAsCompleted 调度函数。我们通过 todoList 进行映射,渲染待办事项,并在其旁边添加一个 remove(X) 按钮。点击某项时,我们会将其标记为已完成;点击 X 按钮时,我们会将其从列表中移除。
步骤5:最后一步,将以上两个组件包装到Provider中。
//Final Wrapper
export default function App() {
return (
<Provider>
<AddTodo />
<TodoList />
</Provider>
);
}
这是代码和预览的工作示例版本。您可以打开沙盒获取完整版代码。
文章来源:https://dev.to/eswaraprakash/react-usecontext-and-usereducer-hooks-2pkm