We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

Hook์˜ ๊ทœ์น™

Hook์€ React 16.8์— ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. Hook์€ class๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ state์™€ ๋‹ค๋ฅธ React์˜ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

Hook์€ JavaScript ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Hook์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋‘ ๊ฐ€์ง€ ๊ทœ์น™์„ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๊ทœ์น™๋“ค์„ ์ž๋™์œผ๋กœ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•œ linter ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ƒ์œ„(at the Top Level)์—์„œ๋งŒ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ ํ˜น์€ ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  early return์ด ์‹คํ–‰๋˜๊ธฐ ์ „์— ํ•ญ์ƒ React ํ•จ์ˆ˜์˜ ์ตœ์ƒ์œ„(at the top level)์—์„œ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ๋™์ผํ•œ ์ˆœ์„œ๋กœ Hook์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ ์€ React๊ฐ€ useState ์™€ useEffect ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š” ์ค‘์—๋„ Hook์˜ ์ƒํƒœ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์ด ์ ์— ๋Œ€ํ•ด์„œ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์•„๋ž˜์—์„œ ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ค์ง React ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

Hook์„ ์ผ๋ฐ˜์ ์ธ JavaScript ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  ์•„๋ž˜์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • โœ… React ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ Hook์„ ํ˜ธ์ถœํ•˜์„ธ์š”.
  • โœ… Custom Hook์—์„œ Hook์„ ํ˜ธ์ถœํ•˜์„ธ์š”. (๋‹ค์Œ ํŽ˜์ด์ง€์—์„œ ์ด ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค)

์ด ๊ทœ์น™์„ ์ง€ํ‚ค๋ฉด ์ปดํฌ๋„ŒํŠธ์˜ ๋ชจ๋“  ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์†Œ์Šค์ฝ”๋“œ์—์„œ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณด์ด๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ESLint ํ”Œ๋Ÿฌ๊ทธ์ธ

์šฐ๋ฆฌ๋Š” ์ด ๋‘ ๊ฐ€์ง€ ๊ทœ์น™์„ ๊ฐ•์ œํ•˜๋Š” eslint-plugin-react-hooks ๋ผ๋Š” ESLint ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์€ Create React App์— ๊ธฐ๋ณธ์ ์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

npm install eslint-plugin-react-hooks --save-dev
// ESLint ์„ค์ • ํŒŒ์ผ
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
    "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
  }
}

์–ด๋–ป๊ฒŒ ๋‚˜๋งŒ์˜ Hook์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์„ค๋ช…ํ•˜๋Š” ๋‹ค์Œ ์žฅ์œผ๋กœ ์ง€๊ธˆ ๋„˜์–ด๊ฐ€๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์žฅ์—์„œ๋Š” ๊ณ„์†ํ•ด์„œ ์ด๋Ÿฌํ•œ ๊ทœ์น™๋“ค์˜ ๋…ผ๋ฆฌ์  ๊ทผ๊ฑฐ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

์„ค๋ช…

์ด์ „์— ๋ฐฐ์› ๋“ฏ์ด ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ State๋‚˜ Effect Hook์„ ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

function Form() {
  // 1. name์ด๋ผ๋Š” state ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  const [name, setName] = useState('Mary');

  // 2. Effect๋ฅผ ์‚ฌ์šฉํ•ด ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์„ธ์š”.
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  // 3. surname์ด๋ผ๋Š” state ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  const [surname, setSurname] = useState('Poppins');

  // 4. Effect๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ œ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

๊ทธ๋ ‡๋‹ค๋ฉด React๋Š” ์–ด๋–ป๊ฒŒ ํŠน์ • state๊ฐ€ ์–ด๋–ค useState ํ˜ธ์ถœ์— ํ•ด๋‹นํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”? ์ •๋‹ต์€ React๊ฐ€ Hook์ด ํ˜ธ์ถœ๋˜๋Š” ์ˆœ์„œ์— ์˜์กดํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ Hook์˜ ํ˜ธ์ถœ ์ˆœ์„œ๋Š” ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์‹œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ------------
// ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง
// ------------
useState('Mary')           // 1. 'Mary'๋ผ๋Š” name state ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
useEffect(persistForm)     // 2. ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ effect๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
useState('Poppins')        // 3. 'Poppins'๋ผ๋Š” surname state ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
useEffect(updateTitle)     // 4. ์ œ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ effect๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

// -------------
// ๋‘ ๋ฒˆ์งธ ๋ Œ๋”๋ง
// -------------
useState('Mary')           // 1. name state ๋ณ€์ˆ˜๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค.(์ธ์ž๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค)
useEffect(persistForm)     // 2. ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ effect๊ฐ€ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.
useState('Poppins')        // 3. surname state ๋ณ€์ˆ˜๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค.(์ธ์ž๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค)
useEffect(updateTitle)     // 4. ์ œ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ effect๊ฐ€ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.

// ...

Hook์˜ ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ๋ Œ๋”๋ง ๊ฐ„์— ๋™์ผํ•˜๋‹ค๋ฉด React๋Š” ์ง€์—ญ์ ์ธ state๋ฅผ ๊ฐ Hook์— ์—ฐ๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Hook์„ ์กฐ๊ฑด๋ฌธ ์•ˆ์—์„œ(์˜ˆ๋ฅผ ๋“ค์–ด persistForm effect) ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ ๊นŒ์š”?

  // ๐Ÿ”ด ์กฐ๊ฑด๋ฌธ์— Hook์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์ฒซ ๋ฒˆ์งธ ๊ทœ์น™์„ ๊นผ์Šต๋‹ˆ๋‹ค
  if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
  }

name !== '' ์กฐ๊ฑด์€ ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง์—์„œ true ๊ธฐ ๋•Œ๋ฌธ์— Hook์€ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ๋‹ค์Œ ๋ Œ๋”๋ง์—์„œ ํผ์„ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด์„œ ์กฐ๊ฑด์„ false๋กœ ๋งŒ๋“ค ๊ฒ๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ๊ฐ„์— Hook์„ ๊ฑด๋„ˆ๋›ฐ๊ธฐ ๋•Œ๋ฌธ์— Hook ํ˜ธ์ถœ ์ˆœ์„œ๋Š” ๋‹ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

useState('Mary')           // 1. name state ๋ณ€์ˆ˜๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค. (์ธ์ž๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค)
// useEffect(persistForm)  // ๐Ÿ”ด Hook์„ ๊ฑด๋„ˆ๋›ฐ์—ˆ์Šต๋‹ˆ๋‹ค!
useState('Poppins')        // ๐Ÿ”ด 2 (3์ด์—ˆ๋˜). surname state ๋ณ€์ˆ˜๋ฅผ ์ฝ๋Š” ๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.
useEffect(updateTitle)     // ๐Ÿ”ด 3 (4์˜€๋˜). ์ œ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ effect๊ฐ€ ๋Œ€์ฒด๋˜๋Š” ๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.

React๋Š” ๋‘ ๋ฒˆ์งธ useState Hook ํ˜ธ์ถœ์— ๋Œ€ํ•ด ๋ฌด์—‡์„ ๋ฐ˜ํ™˜ํ• ์ง€ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. React๋Š” ์ด์ „ ๋ Œ๋”๋ง ๋•Œ์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋‘ ๋ฒˆ์งธ Hook ํ˜ธ์ถœ์ด persistForm effect์™€ ์ผ์น˜ํ•  ๊ฒƒ์ด๋ผ ์˜ˆ์ƒํ–ˆ์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ ์‹œ์ ๋ถ€ํ„ฐ ๊ฑด๋„ˆ๋›ด Hook ๋‹ค์Œ์— ํ˜ธ์ถœ๋˜๋Š” Hook์ด ์ˆœ์„œ๊ฐ€ ํ•˜๋‚˜์”ฉ ๋ฐ€๋ฆฌ๋ฉด์„œ ๋ฒ„๊ทธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ปดํฌ๋„ŒํŠธ ์ตœ์ƒ์œ„(the top of level)์—์„œ Hook์ด ํ˜ธ์ถœ๋˜์–ด์•ผ๋งŒ ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์กฐ๊ฑด๋ถ€๋กœ effect๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค๋ฉด, ์กฐ๊ฑด๋ฌธ์„ Hook ๋‚ด๋ถ€์— ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  useEffect(function persistForm() {
    // ๐Ÿ‘ ๋” ์ด์ƒ ์ฒซ ๋ฒˆ์งธ ๊ทœ์น™์„ ์–ด๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค
    if (name !== '') {
      localStorage.setItem('formData', name);
    }
  });

์ œ๊ณต๋œ lint ๊ทœ์น™์„ ํ™œ์šฉํ•œ๋‹ค๋ฉด ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด์ œ ์™œ Hook์ด ์ด๋Ÿฐ ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ๊ทธ๋ฆฌ๊ณ  ์ด ๊ทœ์น™์ด ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„

๋งˆ์นจ๋‚ด Custom Hook์„ ์ž‘์„ฑํ•˜๋Š” ๋ฒ•์„ ๋ฐฐ์šธ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! Custom Hook์€ React์—์„œ ์ œ๊ณตํ•˜๋Š” Hook์„ ์ถ”์ƒํ™”๋œ ๋กœ์ง์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฒฐํ•ฉํ•ด์ฃผ๊ณ  ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ๊ณตํ†ต์˜ ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.

Is this page useful?Edit this page