LoginSignup
16
4

More than 3 years have passed since last update.

React memoでオブジェクトをpropsで渡したときの動き

Posted at

memoにオブジェクトを渡す

基本的にmemoはshallow比較なのでオブジェクトは比較されないとなっていたので検証する。

import React, { useState, memo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [cnt, setCnt] = useState(0);
  const arr = [];
  return (
    <div className="App">
      {cnt}
      <button onClick={() => setCnt(cnt + 1)}>button</button>
      <Test arr={[]} />
    </div>
  );
}

const Test = memo(({ arr }) => {
  console.log("test", { arr });
  return <div>test</div>;
});

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Nov-09-2019 18-15-16.gif

確かにレンダリングされる。

useMemoつかったら?

やってみる。

import React, { useState, memo, useMemo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [cnt, setCnt] = useState(0);
  const arr = useMemo(() => [], []);
  return (
    <div className="App">
      {cnt}
      <button onClick={() => setCnt(cnt + 1)}>button</button>
      <Test arr={arr} />
    </div>
  );
}

const Test = memo(({ arr }) => {
  console.log("test", { arr });
  return <div>test</div>;
});

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Nov-09-2019 18-20-34.gif

お!!??
レンダリングされない!
なるほど、、

useMemoの更新

少しわかりにくいが、3の倍数のときのみuseMemoで再キャッシュするようにする。
理想は、その時だけmemoしたコンポーネントだけ更新されること。

import React, { useState, memo, useMemo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [cnt, setCnt] = useState(1);
  const [cnt3, setCnt3] = useState(0);
  if (cnt % 3 === 0 && cnt !== cnt3) setCnt3(cnt);
  const arr = useMemo(() => [], [cnt3]);
  return (
    <div className="App">
      {cnt}
      <button onClick={() => setCnt(cnt + 1)}>button</button>
      <Test arr={arr} />
    </div>
  );
}

const Test = memo(({ arr }) => {
  console.log("test", { arr });
  return <div>test</div>;
});

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Nov-09-2019 18-32-41.gif

おー!
想定どおり!!

Objectもやってみる

useMemoを使わない

import React, { useState, memo, useMemo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [cnt, setCnt] = useState(1);
  const obj = {};
  return (
    <div className="App">
      {cnt}
      <button onClick={() => setCnt(cnt + 1)}>button</button>
      <Test arr={obj} />
    </div>
  );
}

const Test = memo(({ obj }) => {
  console.log("test", { obj });
  return <div>test</div>;
});

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Nov-09-2019 18-36-13.gif

レンダリングされる。

useMemoを使う

import React, { useState, memo, useMemo } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [cnt, setCnt] = useState(1);
  const obj = useMemo(() => ({ 'ttt': 1 }), []);
  return (
    <div className="App">
      {cnt}
      <button onClick={() => setCnt(cnt + 1)}>button</button>
      <Test obj={obj} />
    </div>
  );
}

const Test = memo(({ obj }) => {
  console.log("test", obj.ttt);
  return <div>test</div>;
});

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Nov-09-2019 18-40-52.gif

まとめ

memoはオブジェクトを比較してるのではなくて、参照を見ていることが確定したのと、
useMemoを使えば、オブジェクトもmemoの対象にできることがわかった!
これから使っていこう!!

16
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
4