🦔

Reactの再描画について調べた

2020/10/30に公開2

reactの再描画はどのタイミングで行われるのか気になったので調査しました。
間違えてる点があれば光の速さで直すので指摘してください。

再描画されるタイミング

基本的に以下が呼ばれた後にpropsが比較され、必要があれば再描画されます。

- class component
  - this.setState()
  - this.forceUpdate()
- Function component
  - useState
  - useRender

親componentが再描画されれば基本的に子componentはすべて再描画されます。(propsが変わっていようがいまいがかかわらず)

比較方法

shallow compare が使われます。

const object = { a: 1, b: 2 };

object === object // true

object === { a: 1, b: 2 } // false

object === { ...object } // false

中身まで確認しないので比較コストが低いです。

再描画を防ぐためには

再描画されるタイミングで関数や値は別の参照のインスタンスが作られてしまうために再描画されていました。
関数や値は同じ参照のインスタンスが渡されるようにし、子componentがprops比較してから再描画されるようにす必要があります。
useCallback, useMemo, React.memoを使って最適化することができます。

再描画される例

以下の例だと親が再描画されると新しい参照が渡されてしまうので子componentは再描画されてしまいます。

const MemolizedChildComponent = React.memo(props => <ChildComponent { ...props } />);
const ParentComponent = () => {
  const func = () => {
    console.log(1)
  }
  
  const obj = { hoge: "a" };
  
  return <MemolizedChildComponent obj={obj} func={func} />
}

再描画されない例

以下の例だと、親が再描画されても同じ参照を返すので子componentは再描画されません。

const MemolizedChildComponent = React.memo(props => <ChildComponent { ...props } />);
const ParentComponent = () => {
  const func = useCallback(() => {
    console.log(1)
  }, [])
  
  const obj = useMemo(() => ({ hoge: "a" }), []) ;
  
  return <MemolizedChildComponent obj={obj} func={func} />
}

もちろんメモ化するということはコストがかかってしまうのですべてに使ってしまえばいいわけではありません。

いつuseCallback useMemoを使うか迷ったときは

  • 同じ参照のインスタンスを渡したいのか
  • コストの高い計算があるか

このことを意識するのが大切です。

Discussion

aiueo4uaiueo4u

const value = useMemo(() =>1, []) ; これはプリミティブな数値だから const value = 1; のままで大丈夫かと思います!(試していませんが、多分…!)

TsukuniTsukuni

その通りです!光の速さで修正します。ありがとうございます!!