useContext结合useReducer管理状态

2024/8/26 | 字数检测:2452
AI摘要

本文介绍了如何利用React的useReduceruseContext管理复杂状态,以替代useState。文章通过四个步骤详细阐述:首先创建两个Context(一个用于状态,一个用于dispatch函数);其次在顶层组件中将useReducer返回的状态和dispatch函数放入Context提供给子组件;然后子组件可直接使用useContext获取状态和修改函数,无需层层传递;最后推荐将reducer逻辑和Context提供者封装成独立的TasksProvider组件,实现状态逻辑的集中管理和模块化,从而提升代码可维护性。

React

本文参考 React 官方文档:使用 Reducer 和 Context 拓展你的应用,区别于 useState,更好的管理复杂的状态

主要就是利用useContext可以沿着组件向下传值,且无需考虑层级,和useReducer中 Reducer 用于管理状态

第一步:创建 Context

import { createContext } from "react";

export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);

第二步:将 state 和 dispatch 函数放入 context

import { TasksContext, TasksDispatchContext } from "./TasksContext.js";

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
  // ...
  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        ...
      </TasksDispatchContext.Provider>
    </TasksContext.Provider>
  );
}

第三步:在组件树中的任何地方使用 context

现在你不需要任何沿着组件树一层层传递状态和修改状态逻辑,只需要使用 state 和 dispatch,一切变得简单起来

export default function TaskList() {
  const tasks = useContext(TasksContext);
  // ...
export default function AddTask() {
  const [text, setText] = useState('');
  const dispatch = useContext(TasksDispatchContext);
  // ...
  return (
    // ...
    <button onClick={() => {
      setText('');
      dispatch({
        type: 'added',
        id: nextId++,
        text: text,
      });
    }}>Add</button>
    // ...

第四步:让我们把所有东西放到一个文件(非必须,但我推荐这样做)

此时,我们已经完成了随传随用随改变,不过我们的 state 仍然在最顶层组件TaskApp提供,我们试着将整个状态逻辑抽离出去,单独一个文件管理这些状态,显然这是我们想要的,代码模块更加独立 我们连接所有,让那个文件具有这些功能:

  1. 它将管理 reducer 的状态。
  2. 它将提供现有的 context 给组件树。
  3. 它将 把 children 作为 prop,所以你可以传递 JSX。
import { createContext } from "react";
//此处可以导入Reducer,初始状态值

export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
//封装组件
export function TasksProvider({ children }) {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        {children}
      </TasksDispatchContext.Provider>
    </TasksContext.Provider>
  );
}

现在我们一个文件来提供这所有关于状态的一切,使用时不用担心数据混乱,逻辑疯狂抽离让我们代码更好管理维护,让组件的作用更加明确单一,是一个好代码的标准之一,平时写代码要注意它们。

文档细节参考(useContext,useReducer):

更新时间:2024/8/26