IMO 最好使用useMemo 而不是useState。基本上是一样的,contextProviderObject 的引用将在重新渲染期间保留,但如果您需要提供一些状态变量 - 您将能够将此变量添加到 [] deps 数组,以便重新评估 contextProviderObject。
const contextProviderObject = useMemo(
() => ({
showLoginModal: () => setShowLoginModal(true),
onTooManyRequests: () =>
alert("You're trying to often. Please wait a bit")
}),
[]
);
此外,最好添加一些 useCallbacks 来保留函数引用,但无论如何,假设您上下文的所有使用者都将其用作
const { showLoginModal } = useContext(...)
或类似 - 由于 contextProviderObject 未直接使用,因此“优化”方式无用,只有其属性之一在重新渲染之间具有稳定的引用。但是如果你想拥有
const ctx = useContext(...);
// ...
ctx.showLoginModal()
那么可以用 useState 或 useMemo 包装对象,但这并不值得,代码中的复合对象越少 - 在所有这些引用跟踪方面就越好。
我只是用
const contextProviderObject = { .... }
并按原样将其提供给提供者,只需确保使用 useMemo、useState、useCallback 正确处理/保留此对象内部的函数和对象的引用。
const [showLoginModal, setShowLoginModal] = useState(false);
const showLoginModalFn = useCallback(() => {
setShowLoginModal(true);
}, []);
const onTooManyRequestsFn = useCallback(() => {
alert("You're trying to often. Please wait a bit");
}, []);
// In case you will want to use it as
// const ctx = useContext(...);
// ...
// ctx.showLoginModal()
// Also works ok as const { showLoginModal } = useContext(...)
const contextProviderObject = useMemo(
() => ({
showLoginModal: showLoginModalFn,
onTooManyRequests: onTooManyRequestsFn
}),
[showLoginModalFn, onTooManyRequestsFn]
);
// In case you will only use it as
// const { showLoginModal } = useContext(...)
const contextProviderObject1 = {
showLoginModal: showLoginModalFn,
onTooManyRequests: onTooManyRequestsFn
};
但是如果你的团队中有一些初级人员并且你想确保在任何情况下一切都会正常 - 请坚持使用 useMemo 示例。唯一令人烦恼的是当上下文增长时 depsArray 的大小。