hooks-useCallback

โ“What is useCallback

์ธ์ž๋กœ ์ „๋‹ฌํ•œ ํ•จ์ˆ˜๋ฅผ ๊ธฐ์–ตํ•˜์—ฌ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ

export default function Hello() {
  const [name, setName] = useState('');

  const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  const handleClick = () => {
    console.log(`handleClick ์—์„œ name ์˜ ๊ฐ’์€? ${name}`);
  };

  useEffect(() => {
    console.log('handleOnChange ๋ณ€๊ฒฝ!');
  }, [handleClick]);

  return (
    <div>
      <input type='text' value={name} onChange={handleOnChange} />
      <button type='button' onClick={handleClick}>
        Click
      </button>
    </div>
  );
}
  • ์œ ์ €๊ฐ€ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค name ์ƒํƒœ ๊ฐ’์ด ๋ฐ”๋€Œ๊ธฐ ๋•Œ๋ฌธ์—, ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • ๋งค ์ž…๋ ฅ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜๊ธฐ ๋•Œ๋ฌธ์— handleClick ํ•จ์ˆ˜๋„ ๋งค๋ฒˆ ์ดˆ๊ธฐํ™”๋œ๋‹ค.

  • handleClick ํ•จ์ˆ˜๊ฐ€ ๋งค๋ฒˆ ์ดˆ๊ธฐํ™”๋˜์–ด, ํ•จ์ˆ˜ ๊ฐ์ฒด์˜ ์ฃผ์†Œ๊ฐ’์ด ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์—, ๋งค ์ž…๋ ฅ๋งˆ๋‹ค useEffect ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

usecallback

handleClick ํ•จ์ˆ˜๋ฅผ useCallback ์œผ๋กœ ๊ฐ์‹ธ๊ธฐ

export default function Hello() {
  const [name, setName] = useState('๊ธฐ๋ณธ ๊ฐ’');

  const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  const handleClick = useCallback(() => {
    console.log(`handleClick ์—์„œ name ์˜ ๊ฐ’์€? ${name}`);
  }, []);

  useEffect(() => {
    console.log('handleOnChange ๋ณ€๊ฒฝ!');
  }, [handleClick]);

  return (
    <div>
      <input type='text' value={name} onChange={handleOnChange} />
      <button type='button' onClick={handleClick}>
        Click
      </button>
    </div>
  );
}
  • handleClick ํ•จ์ˆ˜๋ฅผ useCallback ์œผ๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜๊ณ , ์˜์กด์„ฑ๋ฐฐ์—ด์— ๋นˆ๋ฐฐ์—ด์„ ์„ค์ •ํ•˜์˜€๋‹ค.

  • ์ž…๋ ฅ ๊ฐ’์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งค๋ฒˆ ๋ฆฌ๋ Œ๋”๋ง ๋˜์–ด๋„, handleClick ํ•จ์ˆ˜๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • Input ์— ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•œ ํ›„์— ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, '๊ธฐ๋ณธ ๊ฐ’'์ด ์ถœ๋ ฅ๋œ๋‹ค.

  • ์˜์กด์„ฑ ๋ฐฐ์—ด์— ๋นˆ๋ฐฐ์—ด์ด ๋“ค์–ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์‹œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๊ณ , ๊ทธ ํ›„์—๋Š” ์•„๋ฌด๋ฆฌ ๋ฆฌ๋ Œ๋”๋ง๋˜์–ด๋„ handleClick ํ•จ์ˆ˜๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๊ณ , ํ•ด๋‹น ์ฃผ์†Œ ๊ฐ’์ด ๋‚จ์•„์žˆ๋‹ค.

usecallback

useCallback ์˜์กด์„ฑ๋ฐฐ์—ด ์ˆ˜์ •

export default function Hello() {
  const [name, setName] = useState('๊ธฐ๋ณธ ๊ฐ’');

  const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  const handleClick = useCallback(() => {
    console.log(`handleClick ์—์„œ name ์˜ ๊ฐ’์€? ${name}`);
  }, [name]);

  useEffect(() => {
    console.log('handleOnChange ๋ณ€๊ฒฝ!');
  }, [handleClick]);

  return (
    <div>
      <input type='text' value={name} onChange={handleOnChange} />
      <button type='button' onClick={handleClick}>
        Click
      </button>
    </div>
  );
}
  • ์ž…๋ ฅ ๊ฐ’์— ๋”ฐ๋ผ์„œ name ์ด๋ผ๋Š” ์ƒํƒœ ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ๋‹ค.

  • useCallback์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— name ๊ฐ’์„ ์„ค์ •ํ•˜์˜€์Œ์œผ๋กœ, ์ž…๋ ฅ ๊ฐ’์— ๋”ฐ๋ผ์„œ ํ•จ์ˆ˜๊ฐ€ ์ดˆ๊ธฐํ™”๋œ๋‹ค.

  • ๋”ฐ๋ผ์„œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์ž…๋ ฅํ•œ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ์ฝ˜์†”์— ํ‘œ์‹œ๋œ๋‹ค.

usecallback

์—ฌ๊ธฐ๊นŒ์ง€ ๋ณด๋ฉด useCallback์„ ์‚ฌ์šฉํ• ๋•Œ์™€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ์˜ ํฐ์ฐจ์ด๊ฐ€ ์—†์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด, ์ด๋ฒคํŠธ์™€ ์ƒํƒœ๋ฅผ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•ด๋ณด์ž!

์ƒํƒœ ๊ฐ’๊ณผ ์ด๋ฒคํŠธ ์ถ”๊ฐ€

export default function Hello() {
  const [name, setName] = useState('๊ธฐ๋ณธ ๊ฐ’');
  const [nickName, setNickName] = useState('');

  const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  const handleOnChange2 = (e: React.ChangeEvent<HTMLInputElement>) => {
    setNickName(e.target.value);
  };

  const handleClick = useCallback(() => {
    console.log(`handleClick ์—์„œ name ์˜ ๊ฐ’์€? ${name}`);
  }, [name]);

  const handleClick2 = useCallback(() => {
    console.log(`handleClick ์—์„œ nickName ์˜ ๊ฐ’์€? ${nickName}`);
  }, [nickName]);

  useEffect(() => {
    console.log('handleOnChange ๋ณ€๊ฒฝ!');
  }, [handleClick]);

  return (
    <div>
      <div>
        <input type='text' value={name} onChange={handleOnChange} />
        <button type='button' onClick={handleClick}>
          Click
        </button>
      </div>
      <div>
        <input type='text' value={nickName} onChange={handleOnChange2} />
        <button type='button' onClick={handleClick2}>
          Click
        </button>
      </div>
    </div>
  );
}
  • ์ƒˆ๋กœ์šด ์ƒํƒœ ๊ฐ’ nickName ์„ ๋งŒ๋“ค๊ณ  ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ, ์ž…๋ ฅํ•ด๋ณด์•˜๋‹ค.

  • nickName ๊ฐ’์„ ์•„๋ฌด๋ฆฌ ๋ณ€๊ฒฝํ•ด๋„ handleClick ํ•จ์ˆ˜๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

usecallback

๋‹ค๋ฅธ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž

์•„๋ž˜ 2๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค.

// /src/component/Hello.tsx
import { useState } from 'react';

import AnotherComponent from './AnotherCount';

export default function Hello() {
  const [count, setCount] = useState < number > 0;
  const [isDark, setIsDark] = useState < boolean > false;

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
    setCount(Number(e.target.value));

  const handleDark = () => setIsDark((prev) => !prev);

  return (
    <div
      style={{
        background: isDark ? 'black' : 'white',
      }}
    >
      <input type='number' value={count} onChange={handleChange} />
      <button type='button' onClick={handleDark}>
        Dark-or-White
      </button>
      <AnotherComponent handleDark={handleDark} />
    </div>
  );
}

// /src/component/AnotherComponent.tsx
import { useEffect } from 'react';

export default function AnotherComponent({
  handleDark,
}: {
  handleDark: () => void;
}) {
  useEffect(() => {
    console.log('Change count in AnotherCount');
  }, [handleDark]);

  return <div>div</div>;
}
  • Hello ์ปดํฌ๋„ŒํŠธ ์•ˆ์— AnotherComponent ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค.

  • Input ์—์„œ ์ˆซ์ž ๊ฐ’์„ ์˜ฌ๋ ค๋„, ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋ถˆ๋ฆฌ์–ธ ๊ฐ’์„ ๋ฐ”๊ฟ”๋„, AnotherComponent ์˜ useEffect ๋Š” ๊ณ„์†ํ•˜์—ฌ ํ˜ธ์ถœ๋œ๋‹ค.

  • count ๊ฐ’์ด๋‚˜ isDark ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด, ์ƒ์œ„ Hello ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋œ๋‹ค.

  • ํ•˜์œ„์˜ AnotherComponent ์˜ useEffect์˜ ์˜์กด์„ฑ๋ฐฐ์—ด์€ handleDark ํ•จ์ˆ˜๊ฐ€ ์„ค์ •๋˜์–ด์žˆ๋Š”๋ฐ, count ๋‚˜ isDark ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๊ธฐ ๋•Œ๋ฌธ์—, handleDark ํ•จ์ˆ˜๋„ ๊ณ„์†ํ•ด์„œ ์ดˆ๊ธฐํ™”๋˜๋Š” ๊ฒƒ์ด ์›์ธ์ด๋‹ค.

  • ํ•ด๊ฒฐ์ฑ…์€ isDark ํ•จ์ˆ˜๋ฅผ useCallback์œผ๋กœ ๊ฐ์‹ธ์ฃผ๋Š” ์ฃผ๊ณ , isDark ๊ฐ’์„ ์˜์กด์„ฑ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

import { useCallback, useState } from 'react';

import AnotherComponent from './AnotherCount';

export default function Hello() {
  const [count, setCount] = useState < number > 0;
  const [isDark, setIsDark] = useState < boolean > false;

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
    setCount(Number(e.target.value));

  const handleDark = useCallback(() => setIsDark((prev) => !prev), [isDark]);

  return (
    <div
      style={{
        background: isDark ? 'black' : 'white',
      }}
    >
      <input type='number' value={count} onChange={handleChange} />
      <button type='button' onClick={handleDark}>
        Dark-or-White
      </button>
      <AnotherComponent handleDark={handleDark} />
    </div>
  );
}

Ref

Last updated