React.memo, useCallback

Jungwon Lee(Jenny)ยท2021๋…„ 5์›” 31์ผ
0

๋ฆฌ์•กํŠธ

๋ชฉ๋ก ๋ณด๊ธฐ
2/2

๐Ÿ“• ์ฝ”๋“œ ์Šค์ฟผ๋“œ ์ˆ˜์—… ๋„์ค‘ ๋„ˆ๋ฌด ์‹ ๊ธฐํ•˜๊ณ  ์ค‘์š”ํ•œ ๋‚ด์šฉ์„ ๋“ฃ๊ฒŒ ๋˜์–ด ์ˆ˜์—… ๋„์ค‘ ๊ณต์œ ํ•ด ์ฃผ์‹  ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ์ธ ๊ณต๋ถ€๋ฅผ ์œ„ํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค ~

React.memo ์‚ฌ์šฉ ์˜ˆ์‹œ

๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋กœ ๋ฆฌ๋ Œ๋”๋ง ์ตœ์ ํ™”์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ•ด๋ด…์‹œ๋‹ค.

import React, { useCallback, useState } from "react";
import "./styles.css";

export default function App() {
  console.log("App");
  const [, setState] = useState();

  return (
    <div className="App">
      <h1>react performance</h1>
      <button onClick={() => setState(Math.random())}>๋ถ€๋ชจ๊ฐ•์ œ๋ Œ๋”๋ง</button>
      <Child data="str" />
    </div>
  );
}

function Child(props) {
  console.log("Child");
  return <div>{props.data}</div>;
}

๋ Œ๋”๋ง ๋ ๋•Œ๋งˆ๋‹ค App์—์„œ console.log("App")์„ ์ฐ๊ณ , ๋ถˆ๋Ÿฌ์˜จ ์ž์‹์ปดํฌ๋„ŒํŠธ๋„ console.log("Child")๋ฅผ ์‹คํ–‰์‹œ์ผœ์ค˜์„œ ๋ฆฌ๋ Œ๋”๋ง์ด ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ์ด๋Ÿฐ ์ฐฝ์ด ๋œน๋‹ˆ๋‹ค.

์ผ๋‹จ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ๋ฒ„ํŠผ์„ 2~3๋ฒˆ ๋ˆ„๋ฅด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

Child์— ๋ณ€ํ™”๊ฐ€ ์—†์ง€๋งŒ ๊ณ„์† ๋ Œ๋”๋ง ๋˜๋Š” ๊ฒƒ์„ ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

React.memo๋กœ child๋ฅผ ๊ฐ์‹ธ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  console.log("App");
  const [, setState] = useState();

  return (
    <div className="App">
      <h1>react performance</h1>
      <button onClick={() => setState(Math.random())}>๋ถ€๋ชจ๊ฐ•์ œ๋ Œ๋”๋ง</button>
      <MemoChild data="str" />
    </div>
  );
}

function Child(props) {
  console.log("Child");
  return <div>{props.data}</div>;
}

export const MemoChild = React.memo(Child);

๊ทธ๋Ÿฌ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

๋ณด์‹œ๋Š”๊ฒƒ๊ณผ ๊ฐ™์ด child๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ˆ˜์—…์„ ๋“ค์œผ๋ฉด์„œ ์ข€ ์‹ ๊ธฐํ•œ? ์ตœ์ ํ™” ํ…Œ์ŠคํŒ… ๋ฐฉ๋ฒ•์ด ์žˆ๊ธฐ์— ๊ธฐ๋ก๊ฒธ ๊ณต์œ ํ•ด๋ด…๋‹ˆ๋‹ค.

Profiler ์‚ฌ์šฉํ•˜์—ฌ ๋ Œ๋”๋ง ์ƒํƒœ ํ™•์ธํ•ด๋ณด๊ธฐ

  1. ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์ผœ์„œ Profiler ํƒญ์„ ์—ด์–ด๋ด…๋‹ˆ๋‹ค.

  1. ๋…นํ™”๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ , ์œ„์˜ ์ฝ”๋“œ์— ์˜ํ•ด ๋œฌ ํŽ˜์ด์ง€์˜ ๋ฒ„ํŠผ์„ 4~5๋ฒˆ์ •๋„ ๋ˆŒ๋Ÿฌ๋ด…๋‹ˆ๋‹ค

  1. ๋ฆฌ๋ Œ๋”๋ง์ด ๋œ ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅธ์ชฝ์˜ ๋ฐ”๋“ค์„ ํด๋ฆญํ•ด๋ด…๋‹ˆ๋‹ค.

ํ˜„์žฌ react.memo๋ฅผ ์“ด ์ƒํƒœ์ด๊ธฐ์—, Child ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๋œน๋‹ˆ๋‹ค.

useCallback ์‚ฌ์šฉ ์˜ˆ์‹œ

clickHandler์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ MemoChild์— ๋‚ด๋ ค์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

import React, { useCallback, useState } from "react";
import "./styles.css";

export default function App() {
  console.log("App");
  const [, setState] = useState();
  const clickHandler = () => console.log("Clicked");

  return (
    <div className="App">
      <h1>react performance</h1>
      <button onClick={() => setState(Math.random())}>๋ถ€๋ชจ๊ฐ•์ œ๋ Œ๋”๋ง</button>
      <MemoChild clickHandler={clickHandler} data="str" />
    </div>
  );
}

function Child(props) {
  console.log("Child");
  return <div>{props.data}</div>;
}

export const MemoChild = React.memo(Child);

๋ญ”๊ฐ€ React.memo๊ฐ€ ์•Œ์•„์„œ "๐Ÿ˜‘์–˜ ๋˜‘๊ฐ™์€ ํ•จ์ˆ˜์—์š” ~" ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ณ  ๋ฆฌ๋ Œ๋”๋ง์„ ๋ง‰์•„์ค„ ๊ฒƒ ๊ฐ™์ง€๋งŒ ์ฝ˜์†”์ฐฝ์„ ๋ณด๋‹ˆ ๊ทธ๋ ‡๊ฒŒ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ ์ด์œ ๋Š”, memo๋กœ ๊ฐ์‹ผ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž๊ธฐ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” clickHandler๋ฅผ ๊ณ„์† ๋น„๊ต๋ฅผ ํ•˜๊ฒ ์ง€๋งŒ, App์ด ๋ฆฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด clickHandler๋ฅผ ์ƒ์„ฑ์‹œํ‚ค๊ณ  ๋‚ด๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, Child๊ฐ€ ๊ณ„์† ๋ฆฌ๋ Œ๋”๋ง์ด ๋œ๋‹ค

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ useCallback์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ผ๋‹ค.

์œ„์—์„œ ํ™•์ธํ•ด๋ณธ Profiler์„ ํ†ตํ•ด ์–ด๋–ค์‹์œผ๋กœ ๋ฆฌ๋ Œ๋”๋ง์ด ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.


Why did this render?์— ๋ณด๋ฉด Props changed๋ผ๋ฉฐ "clickHandler์— ๋ณ€๊ฒฝ์ด ์ƒ๊ฒผ๊ธฐ์— Child๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋๋‹ค~" ๋ผ๊ณ  ์•Œ๋ ค์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘€ ์ฐธ๊ณ : ์ˆ˜์—…๋„์ค‘์— ์™œ ๋‚˜๋Š” ์ € Why did this render์ด ์•ˆ๋œจ์ง€? ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ๋”ฐ๋กœ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค~

ํ†ฑ๋‹ˆ๋ฐ”ํ€ด ์•„์ด์ฝ˜์„ ๋ˆŒ๋Ÿฌ์„œ Profilerํƒญ์— ๋“ค์–ด๊ฐ€๊ณ , ์•„๋ž˜์— ํ‘œ์‹œํ•œ ์ฒดํฌ๋ฅผ ํ™œ์„ฑํ™” ์‹œํ‚ค๋ฉด ๋ฉ๋‹ˆ๋‹ค!

๋‹ค์‹œ ์ฝ”๋“œ๋กœ ๋Œ์•„๊ฐ€์„œ, ์ด์ œ useCallback์„ ์ ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import React, { useCallback, useState } from "react";
import "./styles.css";

export default function App() {
  console.log("App");
  const [, setState] = useState();
  const clickHandler = useCallback(() => {
    console.log("Clicked!");
  }, []);

  return (
    <div className="App">
      <h1>react performance</h1>
      <button onClick={() => setState(Math.random())}>๋ถ€๋ชจ๊ฐ•์ œ๋ Œ๋”๋ง</button>
      <MemoChild clickHandler={clickHandler} data="str" />
    </div>
  );
}

function Child(props) {
  console.log("Child");
  return <div>{props.data}</div>;
}

export const MemoChild = React.memo(Child);

๋ฆฌ๋ Œ๋”๋ง์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ~ ๐Ÿ‘๐Ÿ‘๐Ÿ‘

profile
FE๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ ์‹ถ์€ ๋งํ•˜๋Š” ๊ฐ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€