[React] React.memo๋ž€?

jinyยท2025๋…„ 1์›” 26์ผ

๊ธฐ์ˆ  ๋ฉด์ ‘

๋ชฉ๋ก ๋ณด๊ธฐ
41/78

๐Ÿ—ฃ๏ธ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ์“ฐ์ด๋Š” React.memo์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.

  • ์˜๋„: ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ๊ด€์‹ฌ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์งˆ๋ฌธ

  • ํŒ: ์‚ฌ์šฉ ์˜ˆ์‹œ๋ฅผ ๋“ค๋ฉด ์ข‹๋‹ค.

  • ๋‚˜์˜ ๋‹ต์•ˆ

    React.memo๋Š” ๋ฆฌ์•กํŠธ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

    ๋ฆฌ์•กํŠธ์—์„œ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋ฉด, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋„ ๋ชจ๋‘ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
    ์ด๋•Œ ์ž์‹์˜ props๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋Š”๋ฐ๋„ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋ฉด ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

    React.memo๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์ปดํฌ๋„ŒํŠธ์˜ props๋ฅผ ์–•์€ ๋น„๊ต(shallow compare)ํ•˜๊ณ ,
    props๊ฐ€ ์ด์ „ ๋ Œ๋”์™€ ๋™์ผํ•˜๋‹ค๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    ๋‹ค๋งŒ, props ๋น„๊ต ๊ณผ์ • ์ž์ฒด๋„ ๋น„์šฉ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—,
    ๋ Œ๋”๋ง ๋น„์šฉ์ด ํฐ ์ปดํฌ๋„ŒํŠธ๋‚˜ ์ž์ฃผ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ž์‹์˜ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

  • ์ฃผ์–ด์ง„ ๋‹ต์•ˆ (๋ชจ๋ฒ” ๋‹ต์•ˆ)

    ๋ฆฌ์•กํŠธ์—์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ๊ธฐ์ค€์„ ์‚ดํŽด๋ณด์ž๋ฉด ๋Œ€ํ‘œ์ ์œผ๋กœ ๋ฐ›์•„์˜จ props์˜ ๋ณ€๊ฒฝ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋‘๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
    ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ props์˜ ๋ณ€๊ฒฝ๊ณผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?
    ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ React.memo์ž…๋‹ˆ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด์„œ ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง์—์„œ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์— React.memo๋ฅผ ๋ถ™์—ฌ์ฃผ๊ฒŒ ๋˜๋ฉด ๋ฆฌ์ŠคํŠธ์—์„œ ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์˜ ์•„์ดํ…œ๋งŒ ๋ฆฌ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ๋ฆฌ์ŠคํŠธ ์ „์ฒด๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ด์ง„ ๊ฒ๋‹ˆ๋‹ค.


๐Ÿ“ ๊ฐœ๋… ์ •๋ฆฌ

๐ŸŒŸ React.memo๋ž€?

  • React.memo๋Š” React์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ(Higher Order Component)๋กœ, ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
  • React.memo๋Š” props๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
    ์ฆ‰, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ›๋Š” props๊ฐ€ ์ด์ „ ๋ Œ๋”๋ง๊ณผ ๋™์ผํ•˜๋ฉด, React๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

๐ŸŒŸ React.memo์˜ ์‚ฌ์šฉ๋ฒ•

๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

import React from "react";

const MyComponent = (props) => {
  console.log("๋ Œ๋”๋ง!");
  return <div>{props.value}</div>;
};

// React.memo๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์„œ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
export default React.memo(MyComponent);

์ด์ œ ์ด ์ปดํฌ๋„ŒํŠธ๋Š” props๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•œ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.


๐ŸŒŸ React.memo์˜ ๋™์ž‘ ์›๋ฆฌ

React๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋ฉด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋„ ํ•จ๊ป˜ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.
ํ•˜์ง€๋งŒ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผํ•œ props๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ, React.memo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ „ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

React.memo๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์–•์€ ๋น„๊ต(shallow comparison)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ props์˜ ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค.

  • ์–•์€ ๋น„๊ต: ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ’๋งŒ ๋น„๊ตํ•˜๋ฉฐ, ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ๊ฐ’๊นŒ์ง€ ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐ŸŒŸ React.memo ์‚ฌ์šฉ ์˜ˆ์ œ

์˜ˆ์ œ 1: ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ

import React, { useState } from "react";

const Child = React.memo(({ count }) => {
  console.log("Child ๋ Œ๋”๋ง");
  return <div>Count: {count}</div>;
});

const Parent = () => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>์ฆ๊ฐ€</button>
      <input
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="ํ…์ŠคํŠธ ์ž…๋ ฅ"
      />
      <Child count={count} />
    </div>
  );
};

export default Parent;
  • Child ์ปดํฌ๋„ŒํŠธ๋Š” React.memo๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์œผ๋ฏ€๋กœ, text๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ count๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.
  • React.memo๊ฐ€ ์—†๋‹ค๋ฉด, Parent ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ Child๋„ ํ•ญ์ƒ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.

์˜ˆ์ œ 2: ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜ ์‚ฌ์šฉ
๊ธฐ๋ณธ์ ์œผ๋กœ React.memo๋Š” ์–•์€ ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
๋งŒ์•ฝ props๊ฐ€ ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์ฒ˜๋Ÿผ ์ฐธ์กฐ ํƒ€์ž…์ด๋ผ๋ฉด, React.memo์˜ ๊ธฐ๋ณธ ๋น„๊ต๋กœ๋Š” props๊ฐ€ ํ•ญ์ƒ ๋ณ€๊ฒฝ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค.
์ด๋•Œ ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import React from "react";

const Child = React.memo(
  ({ user }) => {
    console.log("Child ๋ Œ๋”๋ง");
    return <div>User: {user.name}</div>;
  },
  (prevProps, nextProps) => {
    // ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜
    return prevProps.user.name === nextProps.user.name;
  }
);

const Parent = () => {
  const user = { name: "John" };
  
  return <Child user={user} />;
};

export default Parent;
  • ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ์ฒด user๋Š” ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์ฐธ์กฐ๊ฐ’์„ ๊ฐ€์ง€๋ฏ€๋กœ, React.memo๋งŒ ์‚ฌ์šฉํ•˜๋ฉด Child๊ฐ€ ๋งค๋ฒˆ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.

  • ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜๋กœ user.name๋งŒ ๋น„๊ตํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

    โญ React.memo์˜ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜๋ž€?

    • React.memo๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ props์˜ ์–•์€ ๋น„๊ต(shallow comparison)๋ฅผ ํ†ตํ•ด ์ด์ „ props์™€ ์ƒˆ๋กœ์šด props๊ฐ€ ๋™์ผํ•œ์ง€ ํ™•์ธํ•œ๋‹ค.
    • ๋งŒ์•ฝ ๋™์ผํ•˜๋‹ค๋ฉด, ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ๊ทธ๋Ÿฌ๋‚˜ ์–•์€ ๋น„๊ต๋กœ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜(custom comparison function)๋ฅผ ์‚ฌ์šฉํ•ด ๋” ์ •๊ตํ•˜๊ฒŒ ๋น„๊ต ๋กœ์ง์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

    โญ ์‚ฌ์šฉ์ž ๋น„๊ต ํ•จ์ˆ˜์˜ ์—ญํ• 
    React.memo๋Š” ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜(areEqual)๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค.

    1. props ๋น„๊ต ๋ฐฉ์‹ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
      • prevProps(์ด์ „ ๋ Œ๋”๋ง ์‹œ์˜ props)์™€ nextProps(์ด๋ฒˆ ๋ Œ๋”๋ง ์‹œ ์ „๋‹ฌ๋œ props)๋ฅผ ๋น„๊ตํ•œ ํ›„, ๋น„๊ต ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ๋ฆฌ๋ Œ๋”๋ง ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.
        โ†’ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.
        โ†’ false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.
      • ๊ธฐ๋ณธ ์–•์€ ๋น„๊ต๋ฅผ ๋„˜์–ด, ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ๋งŒ ๋น„๊ตํ•˜๊ฑฐ๋‚˜ ๋” ๋ณต์žกํ•œ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐ์ฒด ์†์„ฑ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ, ์ค‘์š”ํ•œ ์†์„ฑ๋งŒ ๋น„๊ตํ•˜๋„๋ก ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    2. ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง ๋ฐฉ์ง€
      • ๋น„๊ต ๋กœ์ง์„ ์ตœ์ ํ™”ํ•˜์—ฌ ๋ Œ๋”๋ง ๋น„์šฉ์ด ๋†’์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
      • React.memo์˜ ๊ธฐ๋ณธ ์–•์€ ๋น„๊ต๋งŒ์œผ๋กœ๋Š” ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์—์„œ ํšจ๊ณผ์ ์ด๋‹ค.

    โญ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜ ๋ถ„์„

    1. prevProps์™€ nextProps์˜ user.name ๊ฐ’์„ ๋น„๊ต
      • prevProps.user.name๊ณผ nextProps.user.name์ด ๊ฐ™์œผ๋ฉด true๋ฅผ ๋ฐ˜ํ™˜
      • prevProps.user.name๊ณผ nextProps.user.name์ด ๋‹ค๋ฅด๋ฉด false๋ฅผ ๋ฐ˜ํ™˜
    2. ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ๋ฆฌ๋ Œ๋”๋ง ์—ฌ๋ถ€ ๊ฒฐ์ •
      • true ๋ฐ˜ํ™˜: React.memo๋Š” ๋ Œ๋”๋ง์„ ๊ฑด๋„ˆ๋’จ๋‹ค. (์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ)
      • false ๋ฐ˜ํ™˜: React.memo๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•œ๋‹ค.

    โญ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜์˜ ์žฅ์ 

    1. ์ฐธ์กฐํ˜• ๋ฐ์ดํ„ฐ ๋น„๊ต
      ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ๋งŒ ๋น„๊ตํ•˜๊ฑฐ๋‚˜, ๊นŠ์€ ๋น„๊ต(deep comparison)๋กœ ๋ฆฌ๋ Œ๋”๋ง์„ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
    (prevProps, nextProps) => {
      return provProps.user.name === nextProps.user.name;
    }
    1. ๋ณต์žกํ•œ ๋น„๊ต ๋กœ์ง ์ ์šฉ
      ์˜ˆ: ๋ฐฐ์—ด์˜ ๊ธธ์ด๋งŒ ๋น„๊ตํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์กฐ๊ฑด์ด ๋งŒ์กฑ๋  ๋•Œ๋งŒ ๋ Œ๋”๋งํ•œ๋‹ค.
    (prevProps, nextProps) => {
      return prevProps.items.length === nextProps.items.length;
    }
    1. ํŠน์ • props ๋ฌด์‹œ
      ์ค‘์š”ํ•˜์ง€ ์•Š์€ props๋Š” ๋ฌด์‹œํ•˜๊ณ  ํ•„์š”ํ•œ props๋งŒ ๋น„๊ต ๊ฐ€๋Šฅ
    (prevProps, nextProps) => {
      return prevProps.user.name === nextProps.user.name; // age๋Š” ๋น„๊ตํ•˜์ง€ ์•Š์Œ
    }
    1. ๋น„๊ต ๋น„์šฉ ์ ˆ๊ฐ
      ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” ๋น„๊ต ๋กœ์ง์„ ๊ฐ„์†Œํ™”ํ•˜์—ฌ ๊ธฐ๋ณธ ์–•์€ ๋น„๊ต๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

    โญ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜์˜ ์ฃผ์˜์ 

    1. ํ•จ์ˆ˜ ์ž‘์„ฑ ์‹œ ์„ฑ๋Šฅ ๊ณ ๋ ค
      • ๋น„๊ต ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋ฏ€๋กœ, ์ง€๋‚˜์น˜๊ฒŒ ๋ณต์žกํ•œ ๋กœ์ง์€ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
      • ๊ฐ„๋‹จํ•˜๊ณ  ํšจ์œจ์ ์ธ ๋น„๊ต ๋กœ์ง์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.
    2. ๋ฆฌ๋ Œ๋”๋ง์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์„ ์ •ํ™•ํžˆ ํŒ๋‹จ
      • ์ž˜๋ชป๋œ ๋น„๊ต ๋กœ์ง์œผ๋กœ ์ธํ•ด ํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
    3. React.memo๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
      • React.memo๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋น„์šฉ์ด ๋†’์€ ์ปดํฌ๋„ŒํŠธ์—์„œ ์œ ์šฉํ•˜๋‹ค.
      • ๋น„์šฉ์ด ๋‚ฎ์€ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” React.memo์™€ ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜๊ฐ€ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

๐ŸŒŸ React.memo๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ 

  1. ์–•์€ ๋น„๊ต์˜ ํ•œ๊ณ„
    • ๊ธฐ๋ณธ์ ์œผ๋กœ React.memo๋Š” ์–•์€ ๋น„๊ต๋งŒ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ, props๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์ด ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒฝ์šฐ์—๋Š” ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
    • ์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•
      1) props๋ฅผ ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ๋กœ ์œ ์ง€ (์˜ˆ: useMemo, useCallback์œผ๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜)
      const Parent = () => {
        const [count, setCount] = useState(0);
        
        // ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ
        const user = { name: "John" };
        
        // useMemo๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•œ ๊ฒฝ์šฐ
        const memoizedUser = useMemo(() => ({ name: "John" }), []);
        
        return <Child user={memoizedUser} />;
      };
      2) ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜ ์‚ฌ์šฉ
  1. ๋ณต์žกํ•œ ๋น„๊ต ํ•จ์ˆ˜๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜
    • ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜๋ฅผ ์ง€๋‚˜์น˜๊ฒŒ ๋ณต์žกํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด, ๋น„๊ต ์—ฐ์‚ฐ ์ž์ฒด๊ฐ€ ์„ฑ๋Šฅ ๋ณ‘๋ชฉ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.
    • ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ปค์Šคํ…€ ๋น„๊ต ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  1. ์ƒํƒœ ๋ณ€ํ™”๋กœ ์ธํ•œ ๋ Œ๋”๋ง
    • React.memo๋Š” props ๋ณ€๊ฒฝ์—๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.
      ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋‚˜ useContext๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด, ์—ฌ์ „ํžˆ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.
  1. ๋ Œ๋”๋ง ๋น„์šฉ์ด ๋‚ฎ์€ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ
    • React.memo๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋น„๊ต ์—ฐ์‚ฐ์— ์•ฝ๊ฐ„์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.
    • ๋”ฐ๋ผ์„œ ๋ Œ๋”๋ง ๋น„์šฉ์ด ๋‚ฎ๊ฑฐ๋‚˜ ์ตœ์ ํ™”๊ฐ€ ๋ถˆํ•„์š”ํ•œ ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๊ตณ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๐ŸŒŸ React.memo์™€ ๊ด€๋ จ๋œ ๋‹ค๋ฅธ ์ตœ์ ํ™” ๊ธฐ๋ฒ•

  1. useMemo์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ
    React.memo๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ „๋‹ฌํ•˜๋Š” props๊ฐ€ ๊ณ„์‚ฐ๋œ ๊ฐ’์ด๋ผ๋ฉด, useMemo๋ฅผ ์‚ฌ์šฉํ•ด props๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•ด์•ผ ํšจ์œจ์ ์ด๋‹ค.

    import React, { useState, useMemo } from "react";
    
    const Child = React.memo(({ value }: { value: number }) => {
      console.log("Child ๋ Œ๋”๋ง");
      return <div>Computed Value: {value}</div>;
    });
    
    const Parent = () => {
      const [count, setCount] = useState<number>(0);
      const [inputValue, setInputValue] = useState<string>("");
      
      // ๊ณ„์‚ฐ ๋น„์šฉ์ด ๋†’์€ ํ•จ์ˆ˜
      const computeExpensiveValue = (num: number) => {
        console.log("๊ฐ’ ๊ณ„์‚ฐ ์ค‘...");
        return num * 2;
      };
      
      // useMemo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
      const memoizedValue = useMemo(() => computeExpensiveValue(count), [count]);
      
      return (
        <div>
          <button onClick={() => setCount((prev) => prev + 1)}>์ฆ๊ฐ€</button>
          <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
          <Child value={memoizedValue} />
        </div>
      );
    };
    
    export default Parent;
    • ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด count๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  Parent๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.
    • computeExpensiveValue๋Š” count๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์‹คํ–‰๋˜๋ฉฐ, ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ ๊ฐ’์ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌ๋œ๋‹ค.
    • React.memo์™€ useMemo๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด ๋ถˆํ•„์š”ํ•œ ์ž์‹ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
  1. useCallback๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ
    ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ๋•Œ, useCallback์„ ์‚ฌ์šฉํ•ด ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

    import React, { useState, useCallback } from "react";
    
    const Child = React.memo(({ onClick }: { onClick: () => void }) => {
      console.log("Child ๋ Œ๋”๋ง");
      return <button onClick={onClick}>ํด๋ฆญ</button>;
    });
    
    const Parent = () => {
      const [count, setCount] = useState(0);
      
      // useCallback์œผ๋กœ ํ•จ์ˆ˜ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
      const handleClick = useCallback(() => {
        console.log("Child ๋ฒ„ํŠผ ํด๋ฆญ");
      }, []);
      
      return (
        <div>
          <button onClick={() => setCount((prev) => prev + 1)}>๋ถ€๋ชจ ๋ฒ„ํŠผ</button>
          <p>๋ถ€๋ชจ ์นด์šดํŠธ: {count}</p>
          <Child onClick={handleClick} />
        </div>
      );
    };
    
    export default Parent;
    • ๋ถ€๋ชจ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด count๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์–ด Parent๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋œ๋‹ค.
    • ํ•˜์ง€๋งŒ, useCallback์œผ๋กœ handleClick์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Child์˜ onClick prop์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋”ฐ๋ผ์„œ React.memo๋Š” Child๋ฅผ ๋ฆฌ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค.
  1. React.useTransition
    React 18์—์„œ ์ถ”๊ฐ€๋œ useTransition์€ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ธด๊ธ‰ ์—…๋ฐ์ดํŠธ์™€ ํŠธ๋žœ์ง€์…˜ ์—…๋ฐ์ดํŠธ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ UI ์—…๋ฐ์ดํŠธ๋ฅผ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋งŒ๋“ ๋‹ค.
    ํŠนํžˆ, ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ์™€ ๊ฐ™์€ ์ž‘์—…์—์„œ ์œ ์šฉํ•˜๋‹ค.

    import React, { useState, useTransition } from "react";
    
    const SlowComponent = React.memo(({ list }: { list: string[] }) => {
      console.log("SlowComponent ๋ Œ๋”๋ง");
      return (
        <ul>
          {list.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
      );
    });
    
    const Parent = () => {
      const [input, setInput] = useState("");
      const [list, setList] = useState<string[]>([]);
      
      // useTransition์œผ๋กœ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ํŠธ๋žœ์ง€์…˜์œผ๋กœ ์ฒ˜๋ฆฌ
      const [isPending, setIsPending] = useTransition();
      
      const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const value = e.target.value;
        setInput(value); // 1. ์ž…๋ ฅ ํ•„๋“œ ์ƒํƒœ๋Š” ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ
        
        // 2. ํŠธ๋žœ์ง€์…˜ ์ƒํƒœ๋กœ ๊ธด ์ž‘์—… ์ฒ˜๋ฆฌ
        startTransition(() => {
          const newList = Array.from({ length: 2000 }, (_, i) => `${value} - ${i}`);
          setList(newList); // ๊ธด ์ž‘์—… (๋ชฉ๋ก ์ƒ์„ฑ ๋ฐ ์—…๋ฐ์ดํŠธ)
        });
      };
      
      return (
        <div>
          <input type="text" value={input} onChange={handleChange} />
          {isPending ? <p>Loading...</p> : <SlowComponent list={list} />}
        </div>
      );
    };
    
    export default Parent;
    • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ์„ ๋ณ€๊ฒฝํ•˜๋ฉด handleChange๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

    • startTransition์€ list ์—…๋ฐ์ดํŠธ๋ฅผ ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ๊ธด๊ธ‰ ์—…๋ฐ์ดํŠธ์ธ ์ž…๋ ฅ ์ฒ˜๋ฆฌ์™€ ๋ณ„๋„๋กœ ์‹คํ–‰ํ•œ๋‹ค.

    • isPending์œผ๋กœ ํŠธ๋žœ์ง€์…˜ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜์—ฌ ๋กœ๋”ฉ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

      โญ ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์˜ ํ•ต์‹ฌ ๊ฐœ๋…

      • ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์€ UI์—์„œ ๊ธด ์ž‘์—…(์˜ˆ: ๋ชฉ๋ก ์ƒ์„ฑ, ๋ Œ๋”๋ง)์„ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
      • ๋ฉ”์ธ ์ž‘์—…(์˜ˆ: ์ž…๋ ฅ ํ•„๋“œ ์—…๋ฐ์ดํŠธ)์€ ์ฆ‰์‹œ ์ฒ˜๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์˜ ๋ถ€๋“œ๋Ÿฌ์›€์„ ์œ ์ง€ํ•œ๋‹ค.
      • React๋Š” ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๋™์•ˆ UI๊ฐ€ "๋Œ€๊ธฐ ์ค‘"์ž„์„ ๋‚˜ํƒ€๋‚ด๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

      โญ ํŠธ๋žœ์ง€์…˜ ์ž‘์—… ๋ถ€๋ถ„ ํ•ด์„

      1. setInput(value) (์ฆ‰๊ฐ์ ์ธ ์—…๋ฐ์ดํŠธ)
        • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ์ž…๋ ฅํ•˜๋Š” ํ…์ŠคํŠธ๋Š” ์ฆ‰์‹œ ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ๋‹ค.
        • ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅด๊ฒŒ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด, ์ด ์ž‘์—…์€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค.
      2. startTransition(() => { ... }) (ํŠธ๋žœ์ง€์…˜ ์ž‘์—…)
        • startTransition์€ React์—๊ฒŒ ์ด ์ž‘์—…์€ ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋กœ ์ฒ˜๋ฆฌํ•ด๋„ ๊ดœ์ฐฎ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค€๋‹ค.
        • ์ฆ‰, React๋Š” ์ด ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋ฉ”์ธ ์ž‘์—…(์ž…๋ ฅ ํ•„๋“œ์˜ ์ฆ‰๊ฐ์ ์ธ ์—…๋ฐ์ดํŠธ)์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌํ•œ๋‹ค.
        • ์—ฌ๊ธฐ์„œ๋Š” ๊ธด ์ž‘์—…์ธ newList ์ƒ์„ฑ๊ณผ setList๋ฅผ ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
      3. isPending ์ƒํƒœ
        • isPending์€ ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ƒํƒœ์ด๋‹ค.
        • ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ด๋ฉด true, ์™„๋ฃŒ๋˜๋ฉด false๊ฐ€ ๋œ๋‹ค.
        • ์ด ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋กœ๋”ฉ ์ค‘์ž„์„ ๋ณด์—ฌ์ฃผ๋Š” ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•œ๋‹ค.

      โญ ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์˜ ๋™์ž‘ ๋ฐฉ์‹

      1. ์šฐ์„ ์ˆœ์œ„ ๋ถ„๋ฆฌ
        React๋Š” ํŠธ๋žœ์žญ์…˜ ์ž‘์—…์„ ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
        ์ฆ‰, ๋” ์ค‘์š”ํ•œ ์ž‘์—…(์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ณผ ๊ฐ™์€)์„ ๋จผ์ € ์ฒ˜๋ฆฌํ•œ ํ›„, ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์„ ๋‚˜์ค‘์— ์ฒ˜๋ฆฌํ•œ๋‹ค.
      2. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
        ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์€ UI ์ฐจ๋‹จ ์—†์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค.
        ์˜ˆ๋ฅผ ๋“ค์–ด, newList ์ƒ์„ฑ๊ณผ setList๊ฐ€ ๊ธด ์ž‘์—…์ด๋ผ๋„ ์ž…๋ ฅ ํ•„๋“œ๋Š” ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ๋œ๋‹ค.
      3. UI ์ƒํƒœ ํ‘œ์‹œ
        isPending์„ ํ™œ์šฉํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ "Loading..." ๊ฐ™์€ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
        ํŠธ๋žœ์ง€์…˜ ์ž‘์—…์ด ๋๋งˆ๋…€ React๋Š” UI๋ฅผ ์ƒˆ๋กญ๊ฒŒ ๋ Œ๋”๋งํ•œ๋‹ค.

      โญ useTransition์˜ ์ด์ 

      1. ๋” ๋‚˜์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜
        • ๋ฉ”์ธ ์ž‘์—…(์ž…๋ ฅ ํ•„๋“œ ์—…๋ฐ์ดํŠธ)์„ ์ฆ‰๊ฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ž…๋ ฅ์˜ ์ง€์—ฐ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
        • ์‚ฌ์šฉ์ž์—๊ฒŒ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•จ์œผ๋กœ์จ UI๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ํ˜„์ƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
      2. ๊ธด ์ž‘์—…์˜ ๋ถ„๋ฆฌ
        • CPU ๋ฆฌ์†Œ์Šค๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•œ ๊ธด ์ž‘์—…์„ ํŠธ๋žœ์ง€์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ UI ์ฐจ๋‹จ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
      3. React์˜ ์šฐ์„ ์ˆœ์œ„ ๊ด€๋ฆฌ ํ™œ์šฉ
        • React์˜ ์Šค์ผ€์ค„๋ง ์‹œ์Šคํ…œ์„ ํ™œ์šฉํ•˜์—ฌ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‚˜๋ˆ„๊ณ  UI ์‘๋‹ต์„ฑ์„ ๊ฐœ์„ ํ•œ๋‹ค.
  1. React.useDeferredValue
    useDeferredValue๋Š” ํ˜„์žฌ ๊ฐ’์˜ ์ง€์—ฐ๋œ(deferred) ๋ฒ„์ „์„ ์ œ๊ณตํ•˜์—ฌ, ๊ธด๊ธ‰ ์ƒํƒœ ์—…๋ฐ์ดํŠธ์™€ ๋А๋ฆฐ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

    import React, { useState, useDeferredValue } from "react";
    
    const SlowComponent = React.memo(({ list }: { list: string[] }) => {
      console.log("SlowComponent ๋ Œ๋”๋ง");
      return (
        <ul>
          {list.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
      );
    });
    
    const Parent = () => {
      const [input, setInput] = useState("");
      const list = Array.from({ length: 2000 }, (_, i) => `${input} - ${i}`);
      
      // ์ž…๋ ฅ๋œ ๊ฐ’์„ ์ง€์—ฐ๋œ ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌ
      const deferredList = useDeferredValue(list);
      
      return (
        <div>
          <input type="text" value={input} onChange={(e) => setInput(e.target.value)} />
          <SlowComponent list={deferredList} />
        </div>
      );
    };
    
    export default Parent;
    • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ์„ ๋ณ€๊ฒฝํ•˜๋ฉด list๊ฐ€ ์ฆ‰์‹œ ์ƒ์„ฑ๋œ๋‹ค.

    • useDeferredValue๋Š” ์ง€์—ฐ๋œ list ๊ฐ’์„ SlowComponent๋กœ ์ „๋‹ฌํ•œ๋‹ค.

    • ์ž…๋ ฅ ์ฒ˜๋ฆฌ๋Š” ๋น ๋ฅด๊ฒŒ, SlowComponent ๋ Œ๋”๋ง์€ ๋’ค๋กœ ๋ฏธ๋ค„์ ธ ๋ถ€๋“œ๋Ÿฌ์šด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•œ๋‹ค.

      โญ ์ฝ”๋“œ์—์„œ useDeferredValue์˜ ์—ญํ• 

      • list: ์ž…๋ ฅ ๊ฐ’(input)์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ƒ์„ฑ๋˜๋Š” ์ฆ‰๊ฐ์ ์ธ ๊ฐ’์ด๋‹ค.
      • deferredList: list ๊ฐ’์„ ์ง€์—ฐ์‹œ์ผœ, React๊ฐ€ ๋ฉ”์ธ ์ž‘์—…(์‚ฌ์šฉ์ž ์ž…๋ ฅ)์— ๋Œ€ํ•œ ๋ Œ๋”๋ง์„ ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๊ณ , ์‹œ๊ฐ„์ด ๋‚  ๋•Œ ๋น„๋กœ์†Œ SlowComponent๊ฐ€ ๋ Œ๋”๋ง๋˜๋„๋ก ๋งŒ๋“ ๋‹ค.

      โญ ์ง€์—ฐ ์ž‘์—…์˜ ๊ตฌ์ฒด์ ์ธ ๋™์ž‘ ๋ฐฉ์‹

      1. ์ฆ‰๊ฐ์ ์ธ ์—…๋ฐ์ดํŠธ
        • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด input ์ƒํƒœ๊ฐ€ ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ๋œ๋‹ค.
        • ์ด ์ƒํƒœ๋Š” list์— ๋ฐ˜์˜๋˜์ง€๋งŒ, list ๊ฐ’์ด ๋ฐ”๋กœ SlowComponent์— ์ „๋‹ฌ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.
      2. ์ง€์—ฐ๋œ ๊ฐ’ ์ œ๊ณต
        • useDeferredValue๋Š” list ๊ฐ’์„ ์ง€์—ฐ์‹œ์ผœ ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
        • ์ฆ‰, React๋Š” ๋จผ์ € ์ž…๋ ฅ ํ•„๋“œ์— ๋Œ€ํ•œ ๋ Œ๋”๋ง์„ ์™„๋ฃŒํ•˜๊ณ , ๊ทธ ์ดํ›„์— ์‹œ๊ฐ„์ด ์žˆ์„ ๋•Œ deferredList๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ SlowComponent๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.
      3. ๋ Œ๋”๋ง ์ตœ์ ํ™”
        • React๋Š” ์ž…๋ ฅ ํ•„๋“œ ์—…๋ฐ์ดํŠธ์™€ ๊ฐ™์€ ์ฆ‰๊ฐ์ ์ธ ์ž‘์—…์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ , ์‹œ๊ฐ„์ด ํ—ˆ์šฉ๋  ๋•Œ SlowComponent๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.
        • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ๋ฐ˜์‘์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ, SlowComponent์™€ ๊ฐ™์ด ๋ Œ๋”๋ง ๋น„์šฉ์ด ํฐ ์ปดํฌ๋„ŒํŠธ์˜ ์—…๋ฐ์ดํŠธ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

      โญ ์™œ useDeferredValue๊ฐ€ ํ•„์š”ํ•œ๊ฐ€?

      • ๋ฌธ์ œ: ๋งŒ์•ฝ useDeferredValue ์—†์ด ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋œ๋‹ค๋ฉด
        1. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ๊ฐ’์„ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค list๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ๋‹ค.
        2. ์ฆ‰๊ฐ์ ์œผ๋กœ SlowComponent๋กœ ์ „๋‹ฌ๋˜์–ด ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.
        3. ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ๊ฐ’์„ ์ž…๋ ฅํ•  ๋•Œ ์ž…๋ ฅ ์ง€์—ฐ(lag)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ํ•ด๊ฒฐ: useDeferredValue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด
        1. ์ž…๋ ฅ ํ•„๋“œ(input) ์—…๋ฐ์ดํŠธ๋Š” ์ฆ‰์‹œ ์ฒ˜๋ฆฌ๋œ๋‹ค.
        2. list ์—…๋ฐ์ดํŠธ๋Š” ์ง€์—ฐ๋˜์–ด React๊ฐ€ ๋‚˜์ค‘์— ์ฒ˜๋ฆฌํ•œ๋‹ค.
        3. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ๋น ๋ฅธ ์‘๋‹ต์„ฑ๊ณผ SlowComponent ๋ Œ๋”๋ง์˜ ํšจ์œจ์„ฑ์„ ๋ชจ๋‘ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

      โญ useDeferredValue์˜ ํŠน์ง•

      1. ์šฐ์„ ์ˆœ์œ„ ๊ด€๋ฆฌ
        ๋†’์€ ์šฐ์„ ์ˆœ์œ„ ์ž‘์—…(์˜ˆ: ์‚ฌ์šฉ์ž ์ž…๋ ฅ)๊ณผ ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„ ์ž‘์—…(์˜ˆ: ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง)์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค.
      2. ์ง€์—ฐ๋œ ๊ฐ’ ์—…๋ฐ์ดํŠธ
        deferredList๋Š” React๊ฐ€ ์—ฌ์œ ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์—…๋ฐ์ดํŠธ๋˜๋ฏ€๋กœ, ๋น„์‹ผ ๋ Œ๋”๋ง ์ž‘์—…์ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

๐ŸŒŸ React.memo๊ฐ€ ์ ํ•ฉํ•œ ์ƒํ™ฉ

  • ์ž์‹ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋น„๊ต์  ๋ฌด๊ฑฐ์šด ๋ Œ๋”๋ง ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , props๊ฐ€ ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ
  • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์ฃผ ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€๋งŒ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ props๋Š” ์ž์ฃผ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

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