簡體   English   中英

在另一個功能組件中聲明 React.memo 是否提供了預期的記憶性能?

[英]Does declaring a React.memo inside another functional component provide the memoization performance as it is intended?

最近我一直在考慮如何根據Dmitri 的如何明智地使用 React.memo 來記憶功能組件的一些子組件。 這些子組件可能會/可能不會使用主要組件的一些道具。

讓組件這樣寫:

export const MainComponent = ({a, b}) => {
  const AComponent = React.memo(() => <p>This is the string of {a}</p>)

  return (
    <div>
      <AComponent />
      <p>This is the string of {b}</p>
    </div>
  )
}

假設MainComponent在其父組件的生命周期中被重新渲染了多次。

const App = () => {
  const [a, setA] = useState(0); // a is update only when a button is pressed
  const [b, setB] = useState(0); // b is updated every 1 second

  const onClick = () => setA(a => a + 1);

  useEffect(() => {
    const interval = setInterval(() => setB(b => b + 1, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
    <div>
      <MainComponent a={a.toString()} b={b.toString()} />
      <button onClick={onClick}>increment a</button>
    </div>
  )
}

我知道隨着App中狀態ab的更新,它需要重新渲染,而這又必須重新渲染依賴於abMainComponent

有2個問題:

  1. Appinterval更新b時, a根本沒有更新,那么MainComponent重新渲染時,是否應該使用 memoized AComponent ,而不支付渲染成本?

  2. 我知道當按下按鈕時, Appa會更新,這會使MainComponent重新渲染; AComponent不能使用 memoized 版本,所以它需要支付重新渲染的成本,但之后它變成了 memoized,為MainComponent的下一次重新渲染做好准備。 我說得對嗎,雖然b在此渲染周期中沒有更新,但<p>This is the string of {b}</p> (未記憶)被重新渲染,支付渲染成本?


我是否正確使用了 React 的備忘錄? 這些替代方案中哪個更好? 它們在功能上是否相同?

  1. React.備忘錄
const AComponent = React.memo(props => <p>This is the string of {props.a}</p>)
  1. 反應.useMemo
const aComponent = React.useMemo(() => <p>This is the string of {a}</>, [a])

// then use it like
return <>{ aComponent }</>

我在一個小實驗中使用了備忘錄,我上傳了圖片也許會有用。

標題.js:

title.js 描述

應用程序.js:

app.js 說明

a) 在我的測試中記憶總是更快(盡管一些博客文章另有說明)。 話雖如此,除非您有一個特別重的組件,或者該組件正在渲染很多孩子,否則您不會看到任何明顯的收益。 如果您正在打字並且該輸入因為父項而重新呈現,它還可以避免您失去焦點。

b) 簡而言之,它們都不起作用, React.memo必須位於渲染 function 之外,它不是維護引用的“魔術” use鈎子函數的一部分。 您必須使用useMemo進行內部渲染。 這是一個示例:不會每秒重新渲染的組件是CComponentDComponent

 const CComponent = React.memo(({ count }) => ( <p>Not re-rendered every second: {count}</p> )); const MainComponent = (props) => { const AComponent = React.memo(() => ( <p>Re-render when parent does: {props.count}</p> )); const BComponent = React.memo(({ count }) => ( <p>Re-render when parent does: {count}</p> )); const DComponent = React.useMemo(() => ( <p>Not re-rendered every second: {props.count}</p> ), [props.count]); return ( <div> <AComponent /> <BComponent count={props.count} /> <CComponent count={props.count} /> {DComponent} <p>parent count: {props.count}</p> <p>parent anotherCounter: {props.anotherCounter}</p> </div> ); }; function App() { const [count, setCount] = React.useState(0); const [anotherCounter, setAnotherCounter] = React.useState(100); React.useEffect(() => { const h = setInterval(() => { setCount((c) => c + 1); }, 6000); const h2 = setInterval(() => { setAnotherCounter((c) => c + 1); }, 1000); return () => { clearInterval(h); clearInterval(h2); }; }, []); return ( <div className="App"> <MainComponent count={count} anotherCounter={anotherCounter} /> </div> ); } ReactDOM.render(<App />, document.querySelector('#container'));
 <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script> <div id="container"></div>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM