ReactJs -当上下文改变时无用的重新渲染-如何解决它?

4xy9mtcn  于 2022-11-04  发布在  React
关注(0)|答案(1)|浏览(152)

我目前在这个网站上工作:https://virgile-hasselmann.vercel.app/。还有一个问题我没有设法解决,我做了一个自定义光标和一个CursorContext来改变它的状态时悬停等...我注意到,当上下文改变它的状态,我的应用程序的每个组件都会重新呈现。为什么会这样?如何解决这个问题?我听说过在ContextProvider下面记忆组件的方法,但似乎不起作用(提供程序下面的组件是我的布局组件,没有问题吗?)
这里是我的应用程序组件,我如何才能防止那些无用的重渲染发生?

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <AuthProvider>
      <CursorProvider>
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </CursorProvider>
    </AuthProvider>
  );
}

我已将布局打包到React.备忘录HOC中,但不起作用:

export default React.memo(Layout);

我尝试在布局组件中使用useMemo:

const Layout = ({ children }: Props): JSX.Element => {
  const { width } = useWindowSize();
  const memoizedJSX = useMemo(() => {
    return (
      <div id="App" className="relative">
        <Head>
          <title>Virgile Hasselmann</title>
          <meta
            name="description"
            content="Virgile Hasselmann, a video and photo portfolio"
          />
          <link rel="icon" href="/favicon.ico" />
        </Head>
        {width! > 768 && <CustomCursor />}
        <header className="fixed w-screen z-50">
          <Navbar />
        </header>
        <main className="min-h-screen">
          <div>{children}</div>
        </main>
      </div>
    );
  }, []);
  return memoizedJSX;
};

也不管用...救命啊!

rekjcdws

rekjcdws1#

问题是你在记忆你使用上下文的地方。任何绑定到上下文的组件在它改变时都将被重新呈现-否则它怎么会有新的上下文状态呢?
您需要做的是将state的绑定只推到它使用的地方。

const Layout = ({ children }: Props): JSX.Element => {
  const { width } = useWindowSize();
  const memoizedJSX = useMemo(() => {
    return (
      <div id="App" className="relative">
        <Head>
          <title>Virgile Hasselmann</title>
          <meta
            name="description"
            content="Virgile Hasselmann, a video and photo portfolio"
          />
          <link rel="icon" href="/favicon.ico" />
        </Head>
        {width! > 768 && <CustomCursor />}
        <header className="fixed w-screen z-50">
          <Navbar />
        </header>
        <main className="min-h-screen">
          <div>{children}</div>
        </main>
      </div>
    );
  }, []);
  return memoizedJSX;
};

结束日期

const Layout = ({ children }: Props): JSX.Element => {
    return (
      <div id="App" className="relative">
        <Head>
          <title>Virgile Hasselmann</title>
          <meta
            name="description"
            content="Virgile Hasselmann, a video and photo portfolio"
          />
          <link rel="icon" href="/favicon.ico" />
        </Head>
        <CursorWithWidth/>
        <header className="fixed w-screen z-50">
          <Navbar />
        </header>
        <main className="min-h-screen">
          <div>{children}</div>
        </main>
      </div>
    );
};
const CursorWithWidth = () => {
  const { width } = useWindowSize();
  return {width! > 768 && <CustomCursor />}
}

现在,当上下文改变时,只有CursorWithWidth会重新呈现。如果你记住CustomCursor --你也会使那个子元素短路!
一般来说,对于组件,你应该小心你的 * 数据绑定 *。并且尝试co-locate your data dependencies。这也方便地清理你的代码,使其更可读,并且你的组件更可重用,因为它们关注的东西更少。(参见Clean Code的第2章)。
记住这一点,另一个好的做法是不要用像useWindowSize()这样的钩子混淆数据绑定。相反,直接在组件的开头使用useContext钩子,可以清楚地知道绑定发生的位置。通常,当一个组件在开始时有一堆数据绑定调用时,您可以看到组件做了太多的事情。您真的需要在同一个位置上所有的数据吗?

相关问题