我有一个关于 React 的上下文 API 的问题。我对 React 的编码水平是初学者。
我正在构建一个具有 8 个上下文的应用程序,它们可能会在项目的未来成倍增加。它们是应用程序不同元素的基本 CRUD 上下文,没有太多复杂性。
当我编写应用程序时,我注意到在我的应用程序中创建了一个嵌套的上下文地狱.js
为了提供更多信息,我将解释该应用程序的一部分。我有一个针对教练、运动员、法院等的 CRUD 行动的背景。
在/src目录下的文件夹结构中,我有一个/context目录,在里面我为每个实体都有一个单独的文件夹。让我们以教练为例。在/src/context/coach目录中,我有 3 个文件。一个coachContext.js,一个coachReducer.js和一个CoachState.js
教练上下文.js文件的内容:
import { createContext } from "react";
const coachContext = createContext();
export default coachContext;
教练减速器.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;
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;
运动员背景、法院背景和我申请的所有其他元素也是如此。
最后,在我的应用程序中.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;
当我完成编写其他上下文时,您可以理解它们将像所有当前状态一样包装路由器。所以会有一个很大的嵌套"问题"。
我想就如何解决此嵌套上下文问题提供任何建议?我是否做出了使用上下文 API 而不是 Redux 开发应用的正确决定?
而不是使用多个上下文提供程序然后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>
);
}
我已经在生产中使用了它,使用一个上下文提供程序,您将值放在该单个提供程序中。这对于一小组函数来说是可管理的,但是随着它变大,我建议使用redux或其他状态管理库之类的东西
还可以考虑使用useMemo
来记忆一些状态元素,useReducer
利用函数来优化上下文的性能(如果它触发深度更新)
你可以使用这个 npm 包 react-pipeline-component
你的代码是这样的:
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";
import {Pipeline, Pipe} from 'react-pipeline-component'
function App() {
return (
<Pipeline components={[
<CourtState children={<Pipe />} />,
<AthleteState children={<Pipe />} />,
<CoachState children={<Pipe />} />,
<Router children={<Pipe />} />,
<Switch children={<Pipe />} />,
<>
<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>
</>
]}/>
);
}
export default App;