如何使用 React Context API 处理多个 Context?

And*_*kon 3 reactjs react-context

我对 React 的 Context API 有疑问。我的 React 编码水平是初学者。

我正在构建一个具有 8 个上下文的应用程序,它们可能会在项目的未来中增加。它们是我的应用程序不同元素的基本 CRUD 上下文,没有太多复杂性。

当我编写应用程序时,我注意到 App.js 中创建了一个嵌套上下文地狱

为了提供更多信息,我将解释该应用程序的一部分。我有一个针对教练、运动员、法庭等的 CRUD 操作的背景。

在/src目录下的文件夹结构中,我有一个/context目录,其中每个实体都有一个单独的文件夹。我们以教练为例。在/src/context/coach目录中我有 3 个文件。coachContext.js、coachReducer.js 和 CoachState.js

coachContext.js 文件的内容:

import { createContext } from "react";

const coachContext = createContext();

export default coachContext;
Run Code Online (Sandbox Code Playgroud)

coachReducer.js 文件的内容:

const coachReducer = (state, action) => {
    switch (action.type) {
        case "GET_COACHES":
            return {
                ...state,
                coaches: action.payload,
            };
        case "SET_CURRENT_COACH":
            return {
                ...state,
                coach: action.payload,
                loading: false,
            };

        default:
            return state;
    }
};

export default coachReducer;

Run Code Online (Sandbox Code Playgroud)

CoachState.js 文件的内容:

import { useReducer } from "react";
import coachContext from "./coachContext";
import coachReducer from "./coachReducer";

const CoachState = (props) => {
    const initialState = {
        coaches: [],
        coach: [],
        loading: false,
    };

    const [state, dispatch] = useReducer(coachReducer, initialState);

    // Function to Add coach
    // Function to Delete coach
    // Function to Set current coach
    // Function to clear current coach
    // Function to Update coach

    return (
        <coachContext.Provider
            value={{
                coaches: state.coaches,
                coach: state.coach,
                loading: state.loading,
            }}
        >
            {props.children}
        </coachContext.Provider>
    );
};

export default CoachState;
Run Code Online (Sandbox Code Playgroud)

运动员背景、法庭背景以及我申请的所有其他要素也是如此。

最后,在我的 App.js 中我有:

import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./pages/Home";
import Coaches from "./pages/Coaches";
import Athletes from "./pages/Athletes";
import Courts from "./pages/Courts";

import CoachState from "./context/coach/CoachState";
import AthleteState from "./context/athlete/AthleteState";
import CourtState from "./context/court/CourtState";

function App() {
    return (
        <CourtState>
          <AthleteState>
            <CoachState>
              <Router>
                <Switch>
                  <Route exact path="/" component={Home}></Route>
                  <Route exact path="/coaches" component={Coaches}></Route>
                  <Route exact path="/athletes" component={Athletes}></Route>
                  <Route exact path="/courts" component={Courts}></Route>
                </Switch>
              </Router>
            </CoachState>
          </AthleteState>
        </CourtState>
    );
}

export default App;
Run Code Online (Sandbox Code Playgroud)

当我写完你可以理解的其他上下文时,它们将像所有当前状态一样包装路由器。所以将会出现一个很大的嵌套“问题”。

我想知道如何解决这个嵌套上下文问题?我是否做出了使用 Context API 而不是 Redux 来开发应用程序的正确决定?

小智 5

您可以在一个上下文提供程序useContext中添加所有所需的值,然后使用自定义挂钩来获取所需的数据或函数,而不是使用多个上下文提供程序从每个上下文提供程序获取每个值

这会减少使用的上下文提供程序的数量,但不会将它们减少到 1 个提供程序,因为并非所有逻辑都会在一个提供程序和另一个提供程序中共享或通用

我使用 Kent C. Dodds 的博客文章“如何有效使用 React Context ”作为高效编写上下文提供程序的参考。

示例:(基本的反示例,但我将解释工作流程)

const MainContext = createContext(null);

const MyComponent = (props) => {
  const [counter, updateCounter] = useState(0);


  const increment = () => {
    updateCounter(counter + 1);
  }

  const decrement = () => {
   updateCounter(counter - 1);
  }

  return(
    <MainContext.Provider value={{counter, increment, decrement}}>
     {children}
   </MainContext.Provider>
  )
}

const useCountNumber = () => {
  const context = useContext(MainContext);
  
  if(context === undefined || context === null) {
    throw new Error('useCounter is not within MainContext scope');
  }
  else {
    return context.counter;
  }
}

const useIncrementCount = () => {

  const context = useContext(MainContext);
  
  if(context === undefined || context === null) {
    throw new Error('useIncrementCount is not within MainContext scope');
  }
  else {
    return context.increment;
  }
}

const useDecrementCount = () => {

  const context = useContext(MainContext);
  
  if(context === undefined || context === null) {
    throw new Error('useDecrementCount is not within MainContext scope');
  }
  else {
    return context.decrement;
  }

}



// in component you wish to use those values

const MyCounter = () => {

  const count = useCountNumber();
  const increment = useIncrementCount();
  const decrement = useDecrementCount();

  return(
   <div>
      {count}

      <button onClick={increment}> +1 </button>
      <button onClick={decrement}> -1 </button>
   </div>

);

}
Run Code Online (Sandbox Code Playgroud)

我已经在生产中使用了它,使用一个上下文提供程序,然后将值放入该单个提供程序中。这对于一小部分函数来说是可以管理的,但随着它变得更大,我会建议使用像 redux 或其他状态管理库这样的东西

还可以考虑用于useMemo记忆一些状态元素,并useReducer利用函数来优化上下文的性能(如果它触发深度更新)