当父组件发生变化时,如何停止子组件不必要的重新渲染

问题描述 投票:0回答:2

所以我目前有一个如下所示的组件:

<Parent>
<Child/>
</Parent>

但是,有时我只想返回:

<Child/>

这可以这样做:

if (condition) {
return <Child/>
}

return (
<Parent>
<Child/>
</Parent>
) 

问题是当

condition
满足(true)时
<Child/>
将重新渲染。遗憾的是,
<Child/>
内的任何道具/状态都没有改变,并且该组件的渲染成本可能相当昂贵。

我不想重写

<Parent/>
,这样它所需要的就成为
<Child/>
的兄弟,因为这是一个很大的改变。

每次满足

<Child/>
时,我该如何停止这种不必要的
condition
渲染。

我尝试过使用

React.memo
,但它没有按照我的预期工作。

javascript reactjs rendering
2个回答
0
投票

不幸的是,我认为您想要实现的目标是不可能的,但是您可以使用类似的功能来解决问题。这样想:不要添加和删除子级(父级)的包装器,而是尝试添加和删除兄弟级。这几乎是同样的事情。我知道您说过您不想修改

Parent
组件的代码,但是我认为这不会影响您的代码。

这是一个例子:

const Parent = ({
  children,
  state,
}: {
  children: ReactNode;
  state: number;
}) => {
  return (
    <>
      {state % 2 === 0 ? (
        <>
          <label>Sibling 1</label>
          <div>Sibling 2</div>
        </>
      ) : (
        ""
      )}
      {children}
    </>
  );
};

如您所见,我没有修改所有内容,而是添加和删除了同级。 另外,记得将 useMemo 添加到子组件中:

const Child = () => {
  const [childState, setChildState] = useState<number>(0);

  return useMemo(() => {
    console.log("Child re-render");
    return (
      <button
        onClick={() => {
          setChildState(childState + 1);
        }}
      >
        Child State: {childState}
      </button>
    );
  }, [childState]);
};

在此示例中,子组件仅应在修改 childState 时重新渲染。如果父级的状态被修改,那么只有兄弟级应该被渲染。这是我的完整代码:

import { ReactNode, useMemo, useState } from "react";

const App = () => {
  const [appState, setAppState] = useState<number>(0);

  return (
    <>
      <button
        onClick={() => {
          setAppState(appState + 1);
        }}
      >
        test
      </button>
      <Parent state={appState}>
        <Child />
      </Parent>
    </>
  );
};

const Parent = ({
  children,
  state,
}: {
  children: ReactNode;
  state: number;
}) => {
  return (
    <>
      {state % 2 === 0 ? (
        <>
          <label>Sibling 1</label>
          <div>Sibling 2</div>
        </>
      ) : (
        ""
      )}
      {children}
    </>
  );
};

const Child = () => {
  const [childState, setChildState] = useState<number>(0);

  return useMemo(() => {
    console.log("Child re-render");
    return (
      <button
        onClick={() => {
          setChildState(childState + 1);
        }}
      >
        Child State: {childState}
      </button>
    );
  }, [childState]);
};

export default App;

0
投票

您尝试过 useMemo 吗?

const child = useMemo(()=><Child/>,[])

if(condition) return child;

//...
© www.soinside.com 2019 - 2024. All rights reserved.