๐Ÿ“Œ useCallback๊ณผ useMemo ์‚ฌ์šฉ ์ด์œ 

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ Œ๋”๋ง ๋  ๋•Œ ๋งˆ๋‹ค ๋ชธ์ฒด๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๋ฏ€๋กœ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ธฐ์–ตํ•˜๊ธฐ ์œ„ํ•ด Hook์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ธฐ์–ต๋œ ์ƒํƒœ ๋˜๋Š” ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

์ด ๋•Œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๋ฉด ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋“ค๋„ ์ƒˆ๋กœ ๊ทธ๋ ค์ง€๋ฏ€๋กœ ๋™์ผ์ฐธ์กฐ๋ฅผ ๋ฒ—์–ด๋‚œ๋‹ค.

๐Ÿธ useCallback

useCallback()์€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ธฐ์–ตํ•ด๋‘๊ณ  ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ ์‹œ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•  ๋•Œ, ๊ธฐ์–ต๋œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์—ฌ ์„ฑ๋Šฅ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export function Counter({ count: initialCount, step }) {
const [count, setCount] = useState(initialCount);

// 1
const handleIncrement = useCallback(() => {
setCount((count) => count + step);
}, [step]);

// 2
const handleDecrement = useCallback(() => {
setCount(count - step);
}, [count, step]);

return (
<div>
<Counter.Button onClick={handleDecrement}>-</Counter.Button>
<Counter.Display>{count}</Counter.Display>
<Counter.Button onClick={handleIncrement}>+</Counter.Button>
</div>
)
  • ๊ธฐ์–ตํ•ด์•ผํ•  ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ํ•จ์ˆ˜์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
  • useEffect()์ฒ˜๋Ÿผ ์ข…์†์„ฑ ๋ฐฐ์—ด์„ ํ†ตํ•ด ์กฐ๊ฑด์— ๋”ฐ๋ผ ๊ธฐ์–ต ์—ฌ๋ถ€๋ฅผ ์žฌ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • 1๋ฒˆ์ฒ˜๋Ÿผ ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒฝ์šฐ๋Š” reduce์ฒ˜๋Ÿผ ํ•จ์ˆ˜๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋Š”๋‹ค. ๊ธฐ์–ต๋˜์–ด์žˆ๋Š” ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • 2๋ฒˆ์ฒ˜๋Ÿผ ๊ฐ’์„ ์ „๋‹ฌํ•ด์ฃผ๋ฉด newState๋กœ ๋ฐ›์•„๋“ค์—ฌ์ ธ์„œ ์ข…์†์„ฑ ๋ฐฐ์—ด์ด ๋ฐ”๋€Œ๋ฉด ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๊ฒŒ๋œ๋‹ค. ๊ธฐ์–ตํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ „๋‹ฌํ•ด์ฃผ๊ณ  ๊ทธ ๊ฐ’์œผ๋กœ ๋ Œ๋”๋งํ•ด์ค€๋‹ค.

๐Ÿ useMemo

1
useCallback(fn, deps) === useMemo(() => fn, deps);

useMemo()๋Š” JavaScript ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ๊ธฐ์–ตํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ธฐ์–ตํ•ด์•ผํ•  ํƒ€์ž…์ด ํ•จ์ˆ˜๋ผ๋ฉด useCallback์„ ์‚ฌ์šฉํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export function Counter({ count: initialCount, step }) {
const [count, setCount] = useState(initialCount);

// useMemo(() => fn, deps)
const handleIncrement = useMemo(
() => () => setCount((prevCount) => prevCount + step),
[step]
);

// useCallback(fn, deps)
const handleDecrement = useCallback(() => {
setCount((prevCount) => prevCount - step);
}, [step]);

// memoized Components
const DecButton = useMemo(
() => <Counter.Button onClick={handleDecrement}>-</Counter.Button>,
[handleDecrement]
);

const IncButton = useMemo(
() => <Counter.Button onClick={handleIncrement}>+</Counter.Button>,
[handleIncrement]
);

return (
<div>
{DecButton}
<Counter.Display>{count}</Counter.Display>
{IncButton}
</div>
);
}
  • useMemo()๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ์–ตํ•œ๋‹ค.
  • ์ข…์†์„ฑ ๋ฐฐ์—ด [count, onDecrement, onIncrement, restProps]์ด ๋ณ€๊ฒฝ๋˜๋ฉด useMemo๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์„ ๊ธฐ์–ตํ•˜๊ณ  ์‹คํ–‰ํ•œ๋‹ค.
  • setCount()๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์–ด ๋™์ผ์ฐธ์กฐ๋ฅผ ํ•˜๋ฏ€๋กœ count ๊ฐ’์„ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค.

๐Ÿ“ ์†Œ๊ฐ

๊ฐ’์„ ๊ธฐ์–ตํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ์ข‹์ง€๋งŒโ€ฆ ๊ตณ์ด ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ๋ณต์žกํ•˜๊ฒŒ ๋˜ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ• ์• ํ•  ํ•„์š”๊ฐ€ ์žˆ์„๊นŒ ?