我有两个钩子,useA
和useB
,它们执行昂贵的操作(假设网络 API 调用),这些值需要使用 React 的上下文 API 保存到全局应用程序状态 (AppContext
)。此外,第二个钩子的行为useB
取决于第一个钩子的结果,useA
。
启动应用程序并创建上下文提供程序后,将调用这些挂钩。 我在上下文提供程序组件中调用钩子,并在第二个钩子中使用相同的上下文。这会产生一个问题,导致信息过时;useB
内部的useContext(AppContext)
无法提供useA
的正确结果。由于useA
的结果需要在useB
钩子的上下文之外,因此我无法将其调用移动到useB
钩子下。否则,这将导致两次调用useA
,一次在上下文提供程序内部,一次在useB
内。
如何解决这个问题?
const useA = () => {
const api = useApi()
const [state, setState] = useState(null)
useEffect(() => {
api.someFn().then((result) => {
setState(result)
})
}, [api])
return state
}
const useB = () => {
const api = useApi()
const { a } = useContext(AppContext)
const [state, setState] = useState(null)
useEffect(() => {
api.someOtherFn(a.someVariable).then((result) => {
setState(result)
})
}, [api, a])
return state
}
const AppContext = createContext({ a: null, b: null })
const AppContextProvider = (children) => {
const a = useA()
const b = useB()
const context = { a, b }
return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}
const App = () => {
return (
<AppContextProvider>
<Router>
...
</Router>
</AppContextProvider>
)
}
也许以下内容会很有用:
const useA = () => {
const api = useApi()
const [state, setState] = useState(null)
useEffect(() => {
api.someFn().then((result) => {
setState(result)
})
}, [api])
return state
}
const useB = (a) => {
const api = useApi()
const [state, setState] = useState(null)
useEffect(() => {
if (a && a.someVariable) {
api.someOtherFn(a.someVariable).then((result) => {
setState(result)
})
}
}, [api, a])
return state
}
const AppContext = createContext({ a: null, b: null })
const AppContextProvider = (children) => {
const a = useA()
const b = useB(a)
// It is not recommended to pack several values into some object and share it via context
// Cause consumers will be retriggered on each call to AppContextProvider
const context = { a, b }
return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}
const App = () => {
return (
<AppContextProvider>
<Router>
...
</Router>
</AppContextProvider>
)
}
请阅读多个上下文 https://reactjs.org/docs/context.html#consuming-multiple-contexts