๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ—‚ WIL/๐Ÿ“ React

โœ๏ธ useMemo, useCallback (+ React.memo + HOC)

by nalong 2022. 8. 10.

๐Ÿ“… ๋ณธ ๊ธ€์€ 2022๋…„ 5์›” 16์ผ ๊ฐœ์ธ github์— ์ž‘์„ฑ๋œ ๊ธ€์ž…๋‹ˆ๋‹ค.

๐Ÿš€ useMemo, useCallback (+ React.memo + HOC)

โญ๏ธ 1์ฐจ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋๋‚˜๊ณ  2์ฐจ ํ”„๋กœ์ ํŠธ์—๋Š” ๋ฆฌ์•กํŠธ์˜ ๋ Œ๋”๋ง ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€๋ จํ•œ hook์„ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ๋‹ค! ๋ผ๋Š” ๋‹ค์ง์„ ํ–ˆ์—ˆ๋Š”๋ฐ, 2์ฐจ ํ”„๋กœ์ ํŠธ๋•Œ ๊ฑฐ์˜ ์‚ฌ์šฉํ•ด๋ณด์ง€ ๋ชปํ–ˆ๋‹ค.
๊ทธ ์ด์œ ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณด๋‹ˆ,  ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ๋‘๋ ค์›€ ๋•Œ๋ฌธ์ด์˜€๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
๊ณต๋ถ€๋ฅผ ์ œ๋Œ€๋กœ ํ•˜์ง€ ์•Š์€ ์ƒํƒœ์˜€๊ธฐ์—  '๊ณผ์—ฐ ์ž˜ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ', '๋„ˆ๋ฌด ์˜ค๋ฒ„์ŠคํŽ™์•„๋‹Œ๊ฐ€? ' , '์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ๋งž๋‚˜? ' ํ•˜๋Š” ๋‘๋ ค์›€๋“ค๋กœ
์ตœ์ ํ™”๋ฅผ ํ•˜์ง€ ๋ชปํ•œ ์ฑ„ 2์ฐจ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋งˆ๋ฌด๋ฆฌ ๋˜์—ˆ๋‹ค. 3์ฐจ ํ”„๋กœ์ ํŠธ์—๋Š” ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ๊ณต๋ถ€ํ•˜์ž!
useMemo, useCallback ์— ๋Œ€ํ•˜์—ฌ ์•Œ์•„๋ณด์ž!

# useMemo๋ž€?

โœ”๏ธ ๊ณต์‹๋ฌธ์„œ์— ์ž˜ ์„ค๋ช…์ด ๋˜์–ด์žˆ๋Š”๋ฐ, ๋ฉ”๋ชจ๋ฆฌ์ œ์ด์…˜๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ผ๋Š” ๋ฌธ์žฅ์ด ํ•ต์‹ฌ์ด๋‹ค.
useMemo๋Š” ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋˜์—‡์„ ๋•Œ์—๋งŒ ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ ๊ฐ’๋งŒ ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
์‰ฝ๊ฒŒ ๋งํ•ด, ๋งจ ์ฒ˜์Œ ๊ฐ’์„ ์บ์‹ฑ์„ ํ•ด๋‘๊ณ  ๋งค๋ฒˆ ๊ณ„์‚ฐ์„ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์บ์‹ฑํ•œ ๊ฐ’์„ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ!

โš ๏ธ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋œ๋‹ค๋Š” ๊ฒƒ -> ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ -> ํ˜ธ์ถœ์ด ๋  ๋•Œ๋งˆ๋‹ค ๋ชจ๋“  ๋‚ด๋ถ€ ๋ณ€์ˆ˜๊ฐ€ ์ดˆ๊ธฐํ™” ๋œ๋‹ค!

 

์˜ˆ์‹œ

function Component() {
  const value = calculate();
  return <div>{value}</div>;
}

function calculate() {
  return 10;
}

Component ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋žœ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค value ๋ผ๋Š” ๋ณ€์ˆ˜๋Š” ์ดˆ๊ธฐํ™”๋˜๊ณ , calculate ํ•จ์ˆ˜๋Š” ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœ๋œ๋‹ค..!! (๋งค์šฐ ๋น„ํšจ์œจ์ )

๐Ÿคฉ  ํ•ด๊ฒฐ

function Component() {
  const value = useMemo(() => calculate(), []);
  return <div>{value}</div>;
}

โœ…  useMemo ๊ตฌ์กฐ

const value = useMemo(() => {
  return calculate();
}), [];

 

โœ”๏ธ ์ฝœ๋ฐฑํ•จ์ˆ˜ : ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•  ๊ฐ’์„ ๊ณ„์‚ฐํ•ด์„œ return.
โœ”๏ธ ์˜์กด์„ฑ ๋ฐฐ์—ด: ๋ฐฐ์—ด ์•ˆ์— ์žˆ๋Š” ์š”์†Œ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋ ๋•Œ๋งŒ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ด์„œ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•  ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•ด์ค€๋‹ค! ๋งŒ์•ฝ ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋นˆ ๋ฐฐ์—ด์ด๋ผ๋ฉด ์ฒ˜์Œ์— ๋งˆ์šดํŠธ ๋ ๋•Œ๋งŒ! ์ดํ›„์—๋Š” ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ ๊ฐ’์„ return!

โญ๏ธ useMemo๊ฐ€ ๋น›์„ ๋ฐœํ•˜๋Š” ๋กœ์ง!

import React, { useEffect, useState } from 'react';

function Memo() {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);

  const location = useMemo(() => {
    return {
      country: isKorea ? 'ํ•œ๊ตญ' : '์™ธ๊ตญ',
    };
  }, [isKorea]);
  // useMemo ๋ฅผ ํ™œ์šฉํ•จ์œผ๋กœ์จ, number ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ location ์žฌ๋ Œ๋”๋ง์„ ๋ง‰์„์ˆ˜ ์žˆ๋‹ค.

  useEffect(() => {
    console.log('useEffect ํ˜ธ์ถœ');
  }, [location]);

  return (
    <div>
      <h3>ํ•˜๋ฃจ์— ๋ช‡๋ผ ๋“œ์‹ฌ?</h3>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <hr />
      <h3>์ง€๊ธˆ ์–ด๋””?</h3>
      <p>๋‚˜๋ผ: {location.country}</p>
      <button onClick={() => setIsKorea(!isKorea)}>๋น„ํ–‰๊ธฐ ํƒ€๊ณ  ๊ฐ€์š”~</button>
    </div>
  );
}
const location = isKorea ? 'ํ•œ๊ตญ' : '์™ธ๊ตญ';

 

์ด๋•Œ location ๋Š” ์›์‹œ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— number ๊ฐ’์ด ๋ฐ”๋€Œ์–ด๋„ useEffect๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค! number ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค location ์€ ์ดˆ๊ธฐํ™”๊ฐ€ ๊ณ„์† ๋˜์ง€๋งŒ, ๋˜‘๊ฐ™์€ string ์„ ํ• ๋‹น๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— useEffect ์‹คํ–‰ X. (useEffect ๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์•ˆ์— ์žˆ๋Š” ์š”์†Œ์˜ ๋‚ด์šฉ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๊ฒฝ์šฐ์—๋งŒ! ์‹คํ–‰๋œ๋‹ค! )

 

const location = { country: isKorea ? 'ํ•œ๊ตญ' : '์™ธ๊ตญ' };

 

๊ฐ์ฒด์ผ๋•Œ๋Š” ์–•์€ ๋ณต์‚ฌ! -> ๊ณ„์† ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— -> ๋งค๋ฒˆ useEffect ํ•จ์ˆ˜ ํ˜ธ์ถœ!

โœ…  ๊ทธ๋Ÿฐ๋ฐ useMemo ์ž˜ ์“ธ ์ผ์ด ์—†๋‹ค...?

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

 

์ด๋ฏธ ๊ณต์‹๋ฌธ์„œ ์ฝ”๋“œ์—์„œ๋„ computeExpensiveValue , ๋น„์‹ผ์—ฐ์‚ฐ์œผ๋กœ ๊ธฐ์žฌ๋˜์–ด์žˆ๋‹ค.
๊ทธ ์ด์œ ๋Š” useMemo ๋ฅผ ๋‚จ์šฉํ•˜๋ฉด ์˜คํžˆ๋ ค ์ปดํฌ๋„ŒํŠธ์˜ ๋ณต์žก๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€๊ณ , ์ฝ”๋“œ๋„ ์ฝ๊ธฐ ์–ด๋ ค์›Œ์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜์„ฑ๋„ ๋–จ์–ด์ง€๊ณ , useMemo ๊ฐ€ ์ ์šฉ๋œ ๋ ˆํผ๋Ÿฐ์Šค๋Š” ์žฌํ™œ์šฉ์„ ์œ„ํ•ด garbage collection ์—์„œ ์ œ์™ธ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์˜คํžˆ๋ ค ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋” ์“ด๋‹ค๊ณ  ํ•œ๋‹ค!

โญ๏ธ ์ฆ‰, useMemo ๋ฅผ ์“ฐ๋Š”๊ฒŒ ์ด๋“์ธ์ง€ ์•„๋‹Œ์ง€ ์ž˜ ํŒ๋‹จํ•ด์•ผํ•จ!

(+ garbage collection : JS ์—”์ง„์—์„œ ๊ณ„์† ๋Š์ž„์—†์ด ์ž‘๋™ -> ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด ์ž๋™ ์‚ญ์ œ)

์ฐธ๊ณ ํ•œ ๋ธ”๋กœ๊ทธ์—์„œ๋Š” useMemo๊ฐ€ ๋น›์„ ๋ฐœํœ˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์€ ๊ทนํžˆ ์ œํ•œ์ ์ด๋ผ๊ณ  ํ•œ๋‹ค!

# useCallback๋ž€?

โœ”๏ธ useCallback์€ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ memoizationํ•˜๋Š” hook์ด๋‹ค. (useMemo ์™€ ๊ฑฐ์˜ ๋น„์Šท -> ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•œ๋‹ค๋Š” ์ฐจ์ด!)

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

์˜ˆ์‹œ

import { useCallback, useEffect, useState } from 'react';
import Box from './Box';

function Callback() {
  const [size, setSize] = useState(100);
  const [isDark, setIsDart] = useState(false);

  const createBoxStyle = useCallback(() => {
    return {
      backgroundColor: 'pink',
      width: `${size}px`,
      height: `${size}px`,
    };
  }, [size]);

  // createBoxStyle์„ useCallback ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๋ฉด์„œ, isDark๊ฐ€ ๋žœ๋”๋ง๋  ๋•Œ, createBoxStyle ํ•จ์ˆ˜๊ฐ€ ์žฌ๋žœ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ง‰์Œ.

  return (
    <div style={{ background: isDark ? 'black' : 'white' }}>
      <input
        type="number"
        value={size}
        onChange={(e) => setSize(e.target.value)}
      />
      <button onClick={() => setIsDart(!isDark)}>Change Theme</button>
      <Box createBoxStyle={createBoxStyle} />
    </div>
  );
}

โš ๏ธ ์ž ๊น!

useCallback ์€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ์˜๋ฏธ์žˆ๋Š” ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ํ• ์ง€ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ผ๋‹จ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์˜ ๋™๋“ฑ์„ฑ์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค!

 

const add1 = () => x + y;
// undefined
const add2 = () => x + y;
// undefined
console.log(add1 === add2);
//false

โญ๏ธ false ๊ฐ€ ๋‚˜์˜ค๋Š” ์ด์œ ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๋„ ๊ฐ์ฒด๋กœ ์ทจ๊ธ‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

๐Ÿง  ๊ทธ๋Ÿผ useCallback๋„ useMemo ์ฒ˜๋Ÿผ ์ž์ฃผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ธ๊ฐ€...?

useCallback ์€ useMemo ๋ณด๋‹ค๋Š” ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฝค ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค!
๋‹ค๋งŒ, ์ค‘์š”ํ•œ ๊ฒƒ์€ ์‚ฌ์šฉ์„ ํ•˜๊ธด ์ „์—! ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ณ  ์‚ฌ์šฉ์ด ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค๊ณ  ํ•œ๋‹ค!

#  React.memo ?

(useCallback ์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๋‹ค๊ฐ€ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค! useCallback ๊ณผ ํ•จ๊ป˜ ์ž์ฃผ ์“ฐ์ธ๋‹ค๊ณ  ํ•œ๋‹ค.)

โœ”๏ธ React.memo๋Š” HOC ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์‹ค HOC ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ž˜ ๋ชจ๋ฅธ๋‹ค...๐Ÿฅฒ ์ผ๋‹จ HOC ๋ถ€ํ„ฐ ๊ณต๋ถ€ํ•ด๋ณด์ž..

# HOC ....?

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

๊ณต์‹๋ฌธ์„œ์˜ ์„ค๋ช…์ด๋‹ค.

์‚ฌ์‹ค ์ž˜ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์•„์„œ, ๋‹ค๋ฅธ ์„ค๋ช…์„ ์ฐพ์•„๋ณด๋˜ ์ค‘ ๊ณ ์ฐจํ•จ์ˆ˜์™€ ๊ฑฐ์˜ ์œ ์‚ฌํ•˜๋‹ค๋Š” ๊ธ€์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค..!!
๊ณ ์ฐจํ•จ์ˆ˜๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌ์ธ์ž๋กœ ๋ฐ›๊ฑฐ๋‚˜, ํ•จ์ˆ˜ ์‹คํ–‰์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ฐ˜ํ™˜ ํ•จ์ˆ˜๋ฅผ ๋งํ•˜๋Š”๋ฐ, ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ์ธ map() ๊ฐ€ ์žˆ๋‹ค.

const nums = [1, 2, 3];
const addNums = nums.map((num) => num + 5);
// ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ์˜ ์‹คํ–‰๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํ„ดํ•œ ๊ฐ’์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•จ.
console.log(addNums); // [6, 7, 8]

 

์–ด๋–ค ๋А๋‚Œ์ธ์ง€...๊ฐ์ด ์•„์ฃผ ์‚ด์ง ์˜ค๋‹ˆ ๋‹ค์‹œ ๊ณ ์ฐจ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ์•„์˜ค์ž.

 

const EnhancedComponent = higherOrderComponent(WrappedComponent);

 

์œ„์˜ ์ฝ”๋“œ์—์„œ higherOrderComponent ๋Š” ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ, WrappedComponent ๋Š” ์ผ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.
EnhancedComponent ๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ํ–ฅ์ƒ๋œ ์ปดํฌ๋„ŒํŠธ!

 

function withProps(Comp, props) {
  // HOC ์ด๋ฆ„ ๊ทœ์น™ : with_
  return function (ownProps) {
    return <Comp {...props} {...ownProps} />;
  };
}
function Hello(props) {
  return (
    <div>
      Hello, {props.name}. I am {props.myName}
    </div>
  );
}

const HelloJohn = withProps(Hello, { name: 'John' });

const App = () => (
  <div>
    <HelloJohn myName="Kim" />
    <HelloJohn myName="Lee" />
  </div>
);

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ์ดํ•ด๊ฐ€ ๋˜์—ˆ์ง€๋งŒ, ํ™•์‹คํ•˜์ง€ ์•Š๋‹ค. ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์ง€๋„ ์•Š์•„์„œ..์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ๋˜ ๋‹ค๋ฅธ ๋А๋‚Œ์ผ ๊ฒƒ ๊ฐ™๋‹ค.
์ผ๋‹จ ์˜ค๋Š˜ ๊ธ€์—์„œ HOC ์„ค๋ช…์€ ์ด์ •๋„๋กœ๋งŒ ํ•˜๊ณ  ์ถ”ํ›„์— !!! ๊ผญ ๋ณด์ถฉ ํ•  ๊ฒƒ์ด๋‹ค!!

# ๋‹ค์‹œ ๋Œ์•„์™€์„œ React.memo ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

React.memo ๋Š” HOC ์ด๋‹ค. ๋ฅผ ์ฝ๊ณ  ์ž ์‹œ HOC ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜์˜€๋‹ค...
๋‹ค์‹œ ๋Œ์•„์˜ค์ž!

 

โœ… ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

export default React.memo(MyComponents);

or

export const updateMyComponents = React.memo(MyComponents);

 

React.memo ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ ๋’ค์—, ์ด์ „์— ๋ Œ๋”๋œ ๊ฒฐ๊ณผ์™€ ๋น„๊ตํ•˜์—ฌ DOM ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค!
์ฆ‰ ์ปดํฌ๋„ŒํŠธ๊ฐ€ React.memo ๋กœ ๋ž˜ํ•‘๋œ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ง• -> ๋‹ค์Œ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚ ๋•Œ props๊ฐ€ ๊ฐ™๋‹ค๋ฉด ๋ฉ”๋ชจ์ด์ง•ํ•œ ๋‚ด์šฉ์„ ์žฌ์‚ฌ์šฉํ•œ๋‹ค!

# React.memo ๋น„๊ต ๋ฐฉ๋ฒ• ์ˆ˜์ •๊ฐ€๋Šฅํ•˜๋‹ค!

useMemo, useCallback ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, props ํ˜น์€ props์˜ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ• ๋•Œ ์–•์€ ๋น„๊ต ๋ฅผ ํ•œ๋‹ค! ์ด๋ฏธ useCallback ์—์„œ ์–ธ๊ธ‰๋˜์—ˆ์ง€๋งŒ, ํ•จ์ˆ˜๋„ ๊ฐ์ฒด๋กœ ์ทจ๊ธ‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

๋Œ€์‹  React.memo ๋Š” ๋น„๊ต ๋ฐฉ์‹์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค! ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋น„๊ตํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋„˜๊ฒจ์ฃผ๋ฉด ๋œ๋‹ค..!!

 

function MyComponents(props) {}

function areEqual(prevProps, nextProps) {
  /*
  nextProp๊ฐ€ prevProps์™€ ๋™์ผํ•œ ๊ฐ’ -> true, ๋‹ค๋ฅด๋‹ค๋ฉด -> false
  */
}

export default React.memo([MyComponents, areEqual]);

โš ๏ธ ์ฝœ๋ฐฑํ•จ์ˆ˜ ์ฃผ์˜ํ•˜์ž!

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ปดํผ๋„ŒํŠธ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ๋‹ค๋ฉด, ์ƒˆ ํ•จ์ˆ˜๊ฐ€ ์ž„์‹œ์ ์œผ๋กœ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค!
์ฐธ๊ณ ํ•œ ๋ธ”๋กœ๊ทธ์— ๊ธฐ์žฌ๋œ ์„ค๋ช…์„ ํ†ตํ•ด ์ดํ•ดํ•ด๋ณด์ž!

 

function Logout({ username, onLogout }) {
  return <div onClick={onLogout}>Logout {username}</div>;
}

const MemoizedLogout = React.memo(Logout);
function MyApp({ store, cookies }) {
  return (
    <div className="main">
      <header>
        <MemoizedLogout
          username={store.username}
          onLogout={() => cookies.clear()}
        />
      </header>
      {store.content}
    </div>
  );
}

 

๋™์ผํ•œ username ๊ฐ’์ด ์ „๋‹ฌ๋˜๋”๋ผ๋„, MemoizedLogout์€ ์ƒˆ๋กœ์šด onLogout ์ฝœ๋ฐฑ ๋•Œ๋ฌธ์— ๋ฆฌ๋ Œ๋”๋ง์„ ํ•˜๊ฒŒ ๋œ๋‹ค.
-> ์ฆ‰ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ์ค‘๋‹จ!

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ onLogout prop์˜ ๊ฐ’์„ ๋งค๋ฒˆ ๋™์ผํ•œ ์ฝœ๋ฐฑ ์ธ์Šคํ„ด์Šค๋กœ ์„ค์ •ํ•˜์—ฌ ๋œ๋‹ค! -> ์ด๋•Œ useCallback ์‚ฌ์šฉ!

 

const MemoizedLogout = React.memo(Logout);

function MyApp({ store, cookies }) {
  const onLogout = useCallback(() => {
    cookies.clear();
  }, []);
  return (
    <div className="main">
      <header>
        <MemoizedLogout username={store.username} onLogout={onLogout} />
      </header>
      {store.content}
    </div>
  );
}

# useCallback, React.memo

useCallback๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜์œ„์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ง‰์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— React.memo ๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ณ ,
React.memo๋งŒ ์‚ฌ์šฉํ•˜๋ฉด, ๋ถ€๋ชจ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด, ์ด๋กœ ์ธํ•ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜์ด ์ค‘๋‹จ๋ ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์— useCallback ์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ดํ•ดํ•˜์˜€๋‹ค..!! (์ถ”ํ›„์— ๋ณด์ถฉ์‚ฌํ•ญ์ด ์žˆ์œผ๋ฉด ์—…๋ฐ์ดํŠธ ํ•  ์˜ˆ์ •! )

# ๋งˆ์ง€๋ง‰์œผ๋กœ React.memo ์–ธ์ œ ์“ฐ๋ฉด ์ข‹์„๊นŒ?

๊ฐ™์€ props ์ž์ฃผ ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ์ปดํฌ๋„ŒํŠธ๋‹ค!
โญ๏ธ ํ•˜์ง€๋งŒ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์•ž์—์„œ๋„ ๊ณ„์† ์–ธ๊ธ‰์ด ๋˜์—ˆ์ง€๋งŒ, ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์™€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ์˜ ์„ฑ๋Šฅ ์ฐจ์ด๋ฅผ ๋น„๊ตํ•œ ํ›„, ์ด๋“์ด ์žˆ์„ ๋•Œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค!!

# ๋А๋‚€์ 

useMemo ์™€ useCallback ์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํžˆ ์ •๋ฆฌํ• ๋ ค๊ณ  ์‹œ์ž‘ํ•œ ๊ธ€์ด, HOC, React.memo ๋กœ ๋งˆ๋ฌด๋ฆฌ ๋˜์—ˆ๋‹ค.
ํ•ญ์ƒ !! ๋งค๋ฒˆ ๋А๋ผ์ง€๋งŒ,,, ๊ณต๋ถ€ํ•˜๋‹ค๋ณด๋ฉด ์ƒˆ๋กœ์šด ๊ณณ์—์„œ ๋˜ ๋‹ค๋ฅธ ๊ณต๋ถ€ํ•ด์•ผํ•˜๋Š” ๊ฒƒ๋“ค์ด ์ƒ๊ธฐ๊ณ ...๋˜ ๊ณต๋ถ€ํ•˜๋ฉด ๋˜ ์ƒ๊ธฐ๊ณ ...์–ด๋ ต๋‹ค...๐Ÿฅฒ
ํ•˜์ง€๋งŒ ํ•œํŽธ์œผ๋กœ ์žฌ๋ฏธ๋„ ์žˆ๋‹ค...!! ๋‹ค๋งŒ, ๊ฐœ๋…์„ ์•ˆ๋‹ค๊ณ  ํ•ด์„œ ๋‹ค ์•„๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ˆ...์‚ฌ์šฉํ•  ๊ธฐํšŒ๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด ๋ฌด์กฐ๊ฑด ์‚ฌ์šฉํ•ด๋ณด์ž!

 

๐Ÿ–‡ Reference

https://merrily-code.tistory.com/11
https://ui.toast.com/weekly-pick/ko_20190731
https://crmrelease.tistory.com/41
https://satisfactoryplace.tistory.com/163
https://sustainable-dev.tistory.com/137
https://www.daleseo.com/react-hooks-use-memo/

https://www.youtube.com/watch?v=XfUF9qLa3mU https://www.youtube.com/watch?v=e-CnI8Q5RY4