React useContext 和 useReducer Hooks。

2025-06-05

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"
};
Enter fullscreen mode Exit fullscreen mode

步骤 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;
  }
};
Enter fullscreen mode Exit fullscreen mode

代码细分:我们使用通常的 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>
  );
};
Enter fullscreen mode Exit fullscreen mode

在这一步中,我们创建 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>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

在这个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>
  );
};
Enter fullscreen mode Exit fullscreen mode

在 TodoList 组件中,我们使用 useContext 订阅 TodoListContext 并获取 todoList 状态、removeTodoItem 和 markAsCompleted 调度函数。我们通过 todoList 进行映射,渲染待办事项,并在其旁边添加一个 remove(X) 按钮。点击某项时,我们会将其标记为已完成;点击 X 按钮时,我们会将其从列表中移除。

步骤5:最后一步,将以上两个组件包装到Provider中。

//Final Wrapper 
export default function App() {
  return (
    <Provider>
      <AddTodo />
      <TodoList />
    </Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

这是代码和预览的工作示例版本。您可以打开沙盒获取完整版代码。

CodeSandbox 中的代码示例链接

文章来源:https://dev.to/eswaraprakash/react-usecontext-and-usereducer-hooks-2pkm
PREV
如何在日本找到软件开发人员的工作
NEXT
Git 和 GitHub 简介 那么...🤔