alswlfl 2022. 11. 24. 00:52

useCallback

ํ•จ์ˆ˜๋ฅผ memoizationํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” hookํ•จ์ˆ˜ → useMemo์™€ ๋น„์Šทํ•œ Hook

๐Ÿ’ก useMemo๋Š” ํŠน์ • ๊ฒฐ๊ณผ๊ฐ’์„ ์žฌ์‚ฌ์šฉ ํ•  ๋•Œ ์‚ฌ์šฉ
     useCallback์€ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ
  • ์ปดํฌ๋„ŒํŠธ์—์„œ props๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฉด Virtual DOM์— ์ƒˆ๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ , ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฐ๊ณผ๋ฌผ์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ์ตœ์ ํ™” ์ž‘์—… → ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ

๊ธฐ๋ณธ ๊ตฌ์กฐ

const memoizedCallback = useCallback(ํ•จ์ˆ˜, ๋ฐฐ์—ด);

์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ: ์ธ์ž๋กœ ๋„˜์–ด์˜จ ํ•จ์ˆ˜

๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ: ๋„˜์–ด์˜จ ๋ฐฐ์—ด ๋‚ด์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๊นŒ์ง€ ์ €์žฅํ•ด๋†“๊ณ  ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ

 

  • ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด๋„ ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์˜์กดํ•˜๋Š” ๊ฐ’๋“ค์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ํ•œ ๊ธฐ์กด ํ•จ์ˆ˜ ๊ณ„์† ๋ฐ˜ํ™˜
const add = () => x+y; 
const add = useCallback(() => x+y, [x,y]);
// x ๋˜๋Š” y ๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜์–ด add๋ณ€์ˆ˜์— ํ• ๋‹น๋˜๊ณ , x์™€ y๊ฐ’์ด ๋™์ผํ•˜๋‹ค๋ฉด
// ๋‹ค์Œ ๋ Œ๋”๋ง ๋•Œ ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ
import React, { useRef, useState, useMemo, useCallback } from "react";

const onChange = useCallback(
    (e) => {
      const { name, value } = e.target;
      setInputs({
        ...inputs,
        [name]: value,
      });
    },
    [inputs]
  );

const onCreate = useCallback(() => {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    setUsers(users.concat(user));
    setInputs({
      username: "",
      email: "",
    });
    nextId.current += 1; //๊ฐ’ ์ˆ˜์ • ์‹œ, .current ๊ฐ’ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๊ณ , ์กฐํšŒํ•  ๋•Œ๋„ .current์กฐํšŒํ•˜๋ฉด ๋จ
  }, [users, username, email]);

const onRemove = useCallback(
    (id) => {
      //user.id๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์›์†Œ๋งŒ ์ถ”์ถœํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“ฆ
      //=user.id๊ฐ€ id์ธ ๊ฒƒ์„ ์ œ๊ฑฐ
      setUsers(users.filter((user) => user.id !== id));
    },
    [users]
  );

  const onToggle = useCallback(
    (id) => {
      setUsers(
        users.map((user) =>
          user.id === id ? { ...user, active: !user.active } : user
        )
      );
    },
    [users]
  );

โ—๏ธ ํ•จ์ˆ˜ ์•ˆ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ƒํƒœ ํ˜น์€ props๊ฐ€ ์žˆ๋‹ค๋ฉด deps ๋ฐฐ์—ด ์•ˆ์— ํฌํ•จ์‹œ์ผœ์•ผ ํ•จ

→ ๋งŒ์•ฝ deps ๋ฐฐ์—ด ์•ˆ์— ํ•ด๋‹น ๊ฐ’์„ ๋„ฃ์ง€ ์•Š์œผ๋ฉด, ํ•จ์ˆ˜ ๋‚ด์—์„œ ํ•ด๋‹น ๊ฐ’๋“ค์„ ์ฐธ์กฐํ•  ๋•Œ ๊ฐ€์žฅ ์ตœ์‹  ๊ฐ’์„ ์ฐธ์กฐํ•œ๋‹ค๊ณ  ๋ณด์žฅ ๋ชปํ•จ

โ—๏ธ props๋กœ ๋ฐ›์•„์˜จ ํ•จ์ˆ˜ ์žˆ์œผ๋ฉด, ์ด ํ•จ์ˆ˜๋„ deps์— ๋„ฃ์–ด์•ผ ํ•จ

 

useCallback์€ useMemo ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง

const onToggle = useMemo(
	() => () => {
		/* ... */
	},
	[users]
);

→ useCallback์„ ์‚ฌ์šฉํ•˜์˜€์„ ๋•Œ, ๋ˆˆ์— ๋„๋Š” ์ตœ์ ํ™”๋Š” ์—†์Œ → ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์ตœ์ ํ™” ์ž‘์—…ํ•ด์ฃผ์–ด์•ผ ์„ฑ๋Šฅ์ด ์ตœ์ ํ™” ๋จ(React DevTools: ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋กœ๊ทธ๋žจ)

 


React.memo๋ฅผ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง ๋ฐฉ์ง€

์ปดํฌ๋„ŒํŠธ์˜ props๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์•˜์„ ๋•Œ, ๋ฆฌ๋ Œ๋”๋ง ๋ฐฉ์ง€ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง ์„ฑ๋Šฅ ์ตœ์ ํ™” ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฆฌ๋ Œ๋”๋ง์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ํ•˜๋„๋ก ์„ค์ •

 

์‚ฌ์šฉ๋ฒ•

export default React.memo(UserList); //์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์„ React.memo๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด ๋จ

 

React.memo์—์„œ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— propsAreEqual ์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ๊ฐ’๋“ค๋งŒ ๋น„๊ต ๊ฐ€๋Šฅ → ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์˜๋„์น˜ ์•Š์€ ๋ฒ„๊ทธ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์›€

export default React.memo(
	UserList,
	(prevProps, nextProps) => prevProps.users === nextProps.users
);

 

์ฃผ์˜ํ•  ์ 

useMemo, useCallback, React.memo๋Š” ์ปดํฌ๋„ŒํŠธ ์„ฑ๋Šฅ์„ ์‹ค์ œ๋กœ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๊ธธ ๊ถŒ์žฅ

ex) ๋ Œ๋”๋ง ์ตœ์ ํ™” ํ•˜์ง€ ์•Š์„ ์ปดํฌ๋„ŒํŠธ์— React.memo๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์€ ๋ถˆํ•„์š”ํ•œ props ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž„