[TECH-QA] ๋ฆฌ์•กํŠธ์˜ useCallback์™€ useMemo

useCallback๊ณผ useMemo๋Š” ๋‘˜ ๋‹ค ReactHooks ์ž…๋‹ˆ๋‹ค.

useCallback

useCallback์€ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ ๋ถˆ ํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ ํ•ฉ๋‹ˆ๋‹ค. useCallback์€ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์žฌ์‚ฌ์šฉ ํ•˜๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ›…์ž…๋‹ˆ๋‹ค. ์˜์กด์„ฑ ๋ฐฐ์—ด(dependency array)์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•œ ๋™์ผํ•œ ํ•จ์ˆ˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ๋•Œ, ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
const memoizedCallback = useCallback(() => {
  // ํ•จ์ˆ˜ ๋กœ์ง
}, [์˜์กด์„ฑ1, ์˜์กด์„ฑ2]);
  • ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— props๋กœ ์ „๋‹ฌ๋˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋งค๋ฒˆ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฒ„ํŠผ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ๋‚˜ ์ด๋ฒคํŠธ ์ฝœ๋ฐฑ์„ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•  ๋•Œ ์œ ์šฉ.
import React, { useState, useCallback } from 'react';

function Child({ onClick }) {
  console.log('Child rendered');
  return <button onClick={onClick}>Click me</button>;
}

function Parent() {
  const [count, setCount] = useState(0);

  // useCallback ์—†์ด ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ์ƒˆ ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋จ
  const handleClick = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []); // ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋นˆ ๊ฒฝ์šฐ, ํ•จ์ˆ˜๋Š” ์ฒ˜์Œ ์ƒ์„ฑ๋œ ํ›„ ์žฌ์‚ฌ์šฉ๋จ

  return (
    <div>
      <p>Count: {count}</p>
      <Child onClick={handleClick} />
    </div>
  );
}

useMemo

useMemo๋Š” ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋ฐ˜ํ™˜๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ ๊ณ„์‚ฐ ๋น„์šฉ์ด ๋†’์€ ๊ฐ’์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์žฌ๊ณ„์‚ฐ์„ ๋ฐฉ์ง€ ํ•ฉ๋‹ˆ๋‹ค. ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์œผ๋ฉด ์ด์ „์— ๊ณ„์‚ฐ๋œ ๊ฐ’(๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑ)์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
const memoizedValue = useMemo(() => {
  // ๊ณ„์‚ฐ ๋กœ์ง
  return ๊ฒฐ๊ณผ๊ฐ’;
}, [์˜์กด์„ฑ1, ์˜์กด์„ฑ2]);
  • ๋ณต์žกํ•œ ์—ฐ์‚ฐ(์˜ˆ: ๋ฐฐ์—ด ํ•„ํ„ฐ๋ง, ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต ๋“ฑ)์˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑ.
  • ๋ Œ๋”๋ง ์ค‘ ๋ถˆํ•„์š”ํ•œ ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ณ  ์‹ถ์„ ๋•Œ.
import React, { useState, useMemo } from 'react';

function ExpensiveComponent() {
  const [number, setNumber] = useState(1);

  // ๋น„์šฉ์ด ํฐ ๊ณ„์‚ฐ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
  const computeExpensiveValue = (num) => {
    console.log('Computing...');
    return num * 1000; // ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋กœ ๊ณฑ์…ˆ ์‚ฌ์šฉ
  };

  // useMemo๋กœ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
  const expensiveResult = useMemo(() => computeExpensiveValue(number), [number]);

  return (
    <div>
      <p>Result: {expensiveResult}</p>
      <button onClick={() => setNumber(number + 1)}>Increment</button>
    </div>
  );
}
์—ฌ๊ธฐ์„œ expensiveResult๋Š” number๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์ƒˆ๋กœ ๊ณ„์‚ฐ๋˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ด์ „ ๊ฐ’์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Computing... ๋กœ๊ทธ๋Š” number๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งŒ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋‘ ํ›… ๋ชจ๋‘ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ ๋„๊ตฌ์ด์ง€๋งŒ, ๋‚จ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ •๋ง ํ•„์š”ํ•œ ์ƒํ™ฉ(์˜ˆ: ์ž์ฃผ ๋ฆฌ๋ Œ๋”๋ง๋˜๊ฑฐ๋‚˜ ๊ณ„์‚ฐ ๋น„์šฉ์ด ํฐ ๊ฒฝ์šฐ)์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.