【问题标题】:Is this context safe from unintentional rerenders?这个上下文是否可以避免无意的重新渲染?
【发布时间】:2023-02-07 01:15:53
【问题描述】:

我的 AppContext 中有两个回调方法(因为我希望能够从任何嵌套组件调用它们)。

因此上下文的值是一个对象。

在 React 上下文文档的 Caveats 部分之后,我将上下文值放入 _app.tsx 内的 useState 中。这是正确的方法吗?

export default function App({ Component, pageProps }: AppProps) {
  
  const [showLoginModal, setShowLoginModal] = useState(false);
  
  [...]

  const [contextProviderObject] = useState({
    showLoginModal: () => setShowLoginModal(true),
    onTooManyRequests: () => alert("You're trying to often. Please wait a bit"),
  });

  return (
    <SSRProvider>
      <AppContext.Provider value={contextProviderObject}>
        <div>
          [...]

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案1】:

    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 的大小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-16
      • 1970-01-01
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 2018-12-21
      • 2021-08-04
      相关资源
      最近更新 更多