防止在包装器组件中启动 useState 的兄弟组件的重新渲染

Posted

技术标签:

【中文标题】防止在包装器组件中启动 useState 的兄弟组件的重新渲染【英文标题】:Prevent rerender of sibling component which initiates a useState in wrapper component 【发布时间】:2020-07-18 23:36:09 【问题描述】:

我对 React 不是很有经验,但我有一个非常简单的设置。

export default function App() 
  const [title, setTitle] = useState("still-empty");

  const myFunction = title => 
    setTitle(title);
  ;

  return (
    <div className="App">
      <ComponentA myFunction=myFunction />
      <br />
      <br />
      <ComponentB title=title />
    </div>
  );




const ComponentA = ( myFunction ) => 
  console.log("Rendering Component A");

  return (
    <div onClick=() => myFunction(Math.random() * 1000)> Component A </div>
  );
;

export default ComponentA;


const ComponentB = ( title ) => 
  return <div> Title : title</div>;
;

export default ComponentB;

这里有一个沙盒来测试这个:https://codesandbox.io/s/musing-cookies-g7szr

请注意,如果您单击“ComponentA”,则会重新渲染确切的 ComponentA(您可以在控制台中看到它),尽管该组件上没有任何道具发生更改。这是我真实用例的简化示例。在我的真实用例中,ComponentA 是一张包含很多东西(缩放、居中)的地图 将被重置。我想防止这些重置以及重新渲染所需的 1 秒。因此,我提出这个简化的例子。

那么如何在不重新渲染 ComponentA 本身的情况下将信息从 ComponentA 传递到 ComponentB?感谢您在这里提供帮助。

【问题讨论】:

您正在更改父组件的状态,这会重新渲染父组件及其子组件,即 ComponentA 和 ComponentB。如果你经常做这样的事情并且不想要任何不必要的重新渲染,那么你可能应该看看像 Redux 这样的东西来允许子组件直接访问状态。 感谢您的回答。是的,我改变了父母的状态。但是 ComponentA 不使用这个状态变量。那么为什么会重新渲染呢?有办法解决吗? ComponentA 不使用状态变量并不重要。当您调用 setState 时,React 会将您的母公司标记为脏并触发它的重新渲染(以及它的子组件 A 和 B)。即使状态中的值没有改变(即如果你传递它已经拥有的相同值),调用 setState 仍然会触发重新渲染。 【参考方案1】:

在 Parent 中使用 useCallback 这样函数就不会一次又一次地创建,而只会在初始渲染时创建。 使用React.memo 以便在没有更改任何道具时组件不会重新渲染。

应用

export default function App() 
  const [title, setTitle] = useState("still-empty");

  const myFunction = useCallback(title => 
    setTitle(title);
  , []);

  return (
    <div className="App">
      <ComponentA myFunction=myFunction />
      <br />
      <br />
      <ComponentB title=title />
    </div>
  );

组件A

import React,  memo  from "react";

const ComponentA = ( myFunction ) => 
  console.log("Rendering Component A");

  return (
    <div onClick=() => myFunction(Math.random() * 1000)> Component A </div>
  );
;

export default memo(ComponentA);

工作演示在这里: https://codesandbox.io/s/affectionate-boyd-v7g2t?file=/src/App.js

【讨论】:

非常感谢。这也适用于我的真实示例。非常感谢。

以上是关于防止在包装器组件中启动 useState 的兄弟组件的重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

React 通过使用 useState 的功能变体来防止重新渲染

如何从 vue-fullpage 包装器中的子组件调用 fullpagejs 方法?

如何防止在单击事件上触发两个相同的 useState 挂钩

如果同级组件中的表单无效,则禁用另一个组件的按钮

使用jquery,从更大的兄弟组中提取每组相邻的兄弟,匹配选择器

兄弟组件怎么粘在一起css