Hook

๊น€๋„๋„›ยท2021๋…„ 10์›” 27์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
4/5

๐Ÿ˜ Hook์˜ ๊ฐœ์š”

Hook์€ React ๋ฒ„์ „ 16.8๋ถ€ํ„ฐ React ์š”์†Œ๋กœ ์ƒˆ๋กœ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
Hook์„ ์ด์šฉํ•˜์—ฌ ๊ธฐ์กด Class ๋ฐ”ํƒ•์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด ์ƒํƒœ ๊ฐ’๊ณผ ์—ฌ๋Ÿฌ React์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hook ๊ธฐ๋Šฅ์„ ํ†ตํ•œ, life cycle, state ์ œ์–ด


๐Ÿ˜† Hook์˜ ์ƒ์„ฑ ๋™๊ธฐ

1.์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ์ƒํƒœ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

๊ธฐ์กด์˜ ๋ฐฉ๋ฒ•: render props, ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ ํŒจํ„ด
      weak: ์ปดํฌ๋„ŒํŠธ์˜ ์žฌ๊ตฌ์„ฑ ๊ฐ•์š”, ์ฝ”๋“œ ์ถ”์  ์–ด๋ ค์›€
            providers, consumers, ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ render props, 
            ๋‹ค๋ฅธ ์ถ”์ƒํ™”์— ๋Œ€ํ•œ ๋ ˆ์ด์–ด๋กœ ๋‘˜๋Ÿฌ์‹ธ์ธ "๋ž˜ํผ์ง€์˜ฅ"(wrapper hell)
Hook์˜ ๋ฐฉ๋ฒ•: ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์ถ”์ƒํ™” ๊ฐ€๋Šฅ
  strength: ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ์™€ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅ ,
            ๊ณ„์ธต์˜ ๋ณ€ํ™” ์—†์ด ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.
            
*๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ(HOC, higher-order component)
 :์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ React์˜ ๊ณ ๊ธ‰ ๊ธฐ์ˆ 
  ์ปดํฌ๋„ŒํŠธ๊ฐ€ UI๋ฅผ props๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐ˜๋ฉด, 
  ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
 
*Render Props
 :React ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜ props๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ ํ…Œํฌ๋‹‰
  render props ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„๋œ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์ฒด์ ์œผ๋กœ ๋ Œ๋”๋ง ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์‹ ,
  react ์—˜๋ฆฌ๋จผํŠธ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
 
  
  	<DataProvider render={data => (
  	   <h1>Hello {data.target}</h1>
	)}/>
            
            

2.๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ํž˜๋“ค์–ด์ง€๋Š” ์ƒํƒœ ๊ด€๋ จ ๋กœ์ง๋“ค๊ณผ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ 
์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์œ ์ง€๋ณด์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 
๊ฐ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์—๋Š” ์ž์ฃผ ๊ด€๋ จ ์—†๋Š” ๋กœ์ง์ด ์„ž์—ฌ๋“ค์–ด๊ฐ€๊ณ ๋Š” ํ•ฉ๋‹ˆ๋‹ค.

ex)
   componentDidMount ์™€ componentDidUpdate๋Š” ์ปดํฌ๋„ŒํŠธ์•ˆ์—์„œ 
   ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์‚ฌ์šฉ ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ,
   ๊ฐ™์€ componentDidMount์—์„œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€
   ๊ด€๊ณ„์—†๋Š” ๋กœ์ง์ด ํฌํ•จ๋˜๊ธฐ๋„ ํ•˜๋ฉฐ,
   componentWillUnmount์—์„œ cleanup ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
   
weak: ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜๋Š” ์ƒํ˜ธ ๊ด€๋ จ ์ฝ”๋“œ๋Š” ๋ถ„๋ฆฌ๋˜์ง€๋งŒ ์ด์™€ ์—ฐ๊ด€ ์—†๋Š” ์ฝ”๋“œ๋“ค์€ 
      ๋‹จ์ผ ๋ฉ”์„œ๋“œ๋กœ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. 
      ์ด๋กœ ์ธํ•ด ๋ฒ„๊ทธ๊ฐ€ ์‰ฝ๊ฒŒ ๋ฐœ์ƒํ•˜๊ณ  ๋ฌด๊ฒฐ์„ฑ์„ ๋„ˆ๋ฌด๋‚˜ ์‰ฝ๊ฒŒ ํ•ด์นฉ๋‹ˆ๋‹ค.

๊ทผ๋ฐ Hook์ด ๋ญ”๊ฐ€์š”?

Hook์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ React state์™€ ์ƒ๋ช…์ฃผ๊ธฐ ๊ธฐ๋Šฅ(lifecycle features)์„ โ€œ์—ฐ๋™(hook into)โ€œํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. Hook์€ class ์•ˆ์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋Œ€์‹  class ์—†์ด React๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Class Componenet life cycle


๐Ÿ“Œ State Hook

  import React, { useState } from 'react';

  function Example() {
    // "count"๋ผ๋Š” ์ƒˆ ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค
    const [count, setCount] = useState(0);
	//useState -> Hook-> state ์ถ”๊ฐ€
        //useState ๊ฐ์ฒด ์•„๋‹ˆ์–ด๋„ ๋œ๋‹ค
    return (
      <div>
        <p>You clicked {count} times</p>
        //setState ๋Œ€์‹  setCount์‚ฌ์šฉ
        <button onClick={() => setCount(count + 1)}>
          Click me
        </button>
      </div>
    );
  }

Hook๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ํด๋ž˜์Šค ์˜ˆ์‹œ

  class Example extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        count: 0
      };
    }

    render() {
      return (
        <div>
          <p>You clicked {this.state.count} times</p>
          <button onClick={() => 
          	this.setState({ count: this.state.count + 1 })}>Click me
          </button>
        </div>
      );
    }
  }

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์˜ ์ฐจ์ด

  1. state ๋ณ€์ˆ˜ ์„ ์–ธ
    (ํ•จ์ˆ˜๋Š” this ๊ฐ€์งˆ์ˆ˜ ์—†์Œ -> useState Hook์„ ์ง์ ‘ ํ˜ธ์ถœ)

  2. state ๊ฐ€์ ธ์˜ค๊ธฐ

  3. state ๊ฐฑ์‹ ํ•˜๊ธฐ
    (ํ•จ์ˆ˜๋Š” setCount์™€ count ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ this๋ฅผ ํ˜ธ์ถœX)

const [fruit, setFruit] = useState('banana'); ์˜ ์˜๋ฏธ

  var fruitStateVariable = useState('banana'); // ๋‘ ๊ฐœ์˜ ์•„์ดํ…œ์ด ์žˆ๋Š” ์Œ์„ ๋ฐ˜ํ™˜
  var fruit = fruitStateVariable[0]; // ์ฒซ ๋ฒˆ์งธ ์•„์ดํ…œ
  var setFruit = fruitStateVariable[1]; // ๋‘ ๋ฒˆ์งธ ์•„์ดํ…œ
  
  useState๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋ฉด 2๊ฐœ์˜ ์•„์ดํ…œ ์Œ์ด ๋“ค์–ด์žˆ๋Š” ๋ฐฐ์—ด๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.
  ์ฒซ ๋ฒˆ์งธ ์•„์ดํ…œ์€ ํ˜„์žฌ ๋ณ€์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๊ณ , 
  ๋‘ ๋ฒˆ์งธ ์•„์ดํ…œ์€ ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ๊ฐฑ์‹ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค

const vs let

useState ์‚ฌ์šฉ์‹œ ๊ฐ’์ด ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์žฌํ• ๋‹น ๋ ํ…๋ฐ const๋ฅผ ์“ฐ๋Š” ์ด์œ :

component๊ฐ€ ๋‹ค์‹œ rendering ๋˜๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜์–ด ์ƒˆ scope๋ฅผ ๋งŒ๋“ค๊ณ  
์ƒˆ๋กญ๊ฒŒ name ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , ์ด์ „ ๋ณ€์ˆ˜์™€๋Š” ๊ด€๋ จ์ด ์—†์–ด์ง€๊ฒŒ ๋˜์–ด const๋กœ ์„ ์–ธํ•œ๋‹ค.

์—ฌ๋Ÿฌ๊ฐœ์˜ state ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?

function ExampleWithManyStates() {
  // ์—ฌ๋Ÿฌ ๊ฐœ์˜ state๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  
  function handleOrangeClick() {
   // this.setState({ fruit: 'orange' })์™€ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.
    setFruit('orange');
  }

๐Ÿš€ Component์˜ LifeCycle

๐Ÿ’ก Component์˜ Lifecycle์€, component๊ฐ€ ํ•˜๋‚˜์˜ ๋…ธ๋“œ๋กœ DOM์— ์˜ฌ๋ผ๊ฐ€๊ณ , ์ˆ˜์ •๋˜๊ณ , ๋‚ด๋ ค์˜ค๋Š” ๊ณผ์ •์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
๐Ÿ‘‰ ์ฆ‰, "mounting" (adding nodes to the DOM), "unmounting" (removing them from the DOM), and "updating" (making changes to nodes already in the DOM) ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

๐Ÿ“Œ Mount ๋งˆ์šดํŠธ

  • ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด DOM ์ƒ์— ์‚ฝ์ž…๋˜๋Š” ๊ฒƒ.
    ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ํŠน์ • ์˜์—ญ์— ๋ผ์›Œ๋„ฃ๋Š” ํ–‰์œ„๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

  • ์˜ˆ๋กœ ReactDOM.render ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ DOM์˜ ํŠน์ • ์˜์—ญ์— ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ผ์›Œ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ณ , ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ๋งˆ์šดํŠธํ•œ๋‹ค๊ณ  ํ‘œํ˜„ํ•œ๋‹ค.

  • < Rendering๊ณผ Mounting >
    ๐Ÿ‘‰ "Rendering" is any time a function component gets called or a class-based render method gets called which returns a set of instructions for creating DOM.
    ๐Ÿ‘‰ "Mounting" is when React "renders" the component for the first time and actually builds the initial DOM from those instructions.
    ๐Ÿ‘‰ ๋ Œ๋”๋ง์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์„ ๋งŒ๋“œ๋Š” ๋ช…๋ น๋“ค์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋งํ•˜๊ณ , ๋งˆ์šดํŒ…์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

  • mount ๋‹จ๊ณ„์˜ class component lifecycle methods
    1. constructor()
    2. static getDerivedStateFromProps()
    3. render()
    4. componentDidMount()

๐Ÿ“Œ Update ์—…๋ฐ์ดํŠธ

  • ์ด๋ฏธ mount ๋˜์–ด DOM์— ์กด์žฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ re-rendering ํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๊ฒƒ. (์ƒˆ๋กœ mount ํ•˜๋Š” ๊ฒƒ ์•„๋‹˜.)

  • A "re-render" is when React calls the function component again to get a new set of instructions on an already mounted component. Re-renders just update the DOM but don't mount since mounting just happens once.

  • ์ปดํฌ๋„ŒํŠธ๋Š” ์•„๋ž˜์˜ ๋„ค ๊ฐ€์ง€ ๊ฒฝ์šฐ์— ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.
    - props๊ฐ€ ๋ฐ”๋€” ๋•Œ
    - state๊ฐ€ ๋ฐ”๋€” ๋•Œ
    - ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ
    - this.forceUpdate๋กœ ๊ฐ•์ œ๋กœ ๋ Œ๋”๋ง์„ ํŠธ๋ฆฌ๊ฑฐํ•  ๋•Œ

  • update ๋‹จ๊ณ„์˜ class component lifecycle methods
    1. static getDerivedStateFromProps()
    2. shouldComponentUpdate()
    3. render()
    4. getSanphotBeforUpdate()
    5. componentDidUpdate()

๐Ÿ“Œ Unmount ์–ธ๋งˆ์šดํŠธ

  • ๋งˆ์šดํŠธ์˜ ๋ฐ˜๋Œ€ ๊ณผ์ •. ์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM์—์„œ ์ œ๊ฑฐ๋˜๋Š” ๊ฒƒ

  • unmount ๋‹จ๊ณ„์˜ class component์—์„œ๋Š” componentWillUnmount() method๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.


โšก๏ธ Effect Hook

side effects(effects)์ด๋ž€,

React ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ตฌ๋…ํ•˜๊ณ , DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋Š” ์ž‘์—…
ํŠน์ง•: ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜๋„ ์žˆ๊ณ , ๋ Œ๋”๋ง ๊ณผ์ •์—์„œ๋Š” ๊ตฌํ˜„ํ•  ์ˆ˜ ์—†๋Š” ์ž‘์—…
Effect Hook, ์ฆ‰ useEffect๋Š” ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์ด๋Ÿฐ side effects๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค
main effect๋Š” render์˜ return()๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

useEffect ๋Š” ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๋‹ด๋‹น

useEffect =ใ€€ componentDidMount ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€+componentDidUpdate ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€+componentWillUnmount

1. ๋งˆ์šดํŠธ ๋ ๋•Œ๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ (componentDidMount)

๋งŒ์•ฝ useEffect ์—์„œ ์„ค์ •ํ•œ ํ•จ์ˆ˜๊ฐ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๊ฐ€์žฅ ์ฒ˜์Œ ๋ Œ๋”๋ง ๋  ๋•Œ๋งŒ ์‹คํ–‰๋˜๊ณ  ์—…๋ฐ์ดํŠธ ํ•  ๊ฒฝ์šฐ์—๋Š” ์‹คํ–‰ ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—” ํ•จ์ˆ˜์˜ ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋น„์–ด์žˆ๋Š” ๋ฐฐ์—ด์„ ๋„ฃ์–ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 useEffect(() => {
    console.log('๋งˆ์šดํŠธ ๋  ๋•Œ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.');
  }, []);

2. ํŠน์ • ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ(componentDidupdate)

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ prevProps์˜ ๊ฐ’์„ ๊ฐ€์ ธ์™€ ๋น„๊ต๋ฅผ ํ•˜์—ฌ ๋กœ์ง์ˆ˜ํ–‰

componentDidUpdate(prevProps, prevState) {
  if (prevProps.value !== this.props.value) {
    doSomething();  
  }
}

useEffect์—์„œ๋Š” ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฐฐ์—ด ์•ˆ์— ๊ฒ€์‚ฌ(์—…๋ฐ์ดํŠธ๋˜๋Š”์ง€)ํ•˜๊ณ  ์‹ถ์€ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ์‹œ๋ฉด ๋œ๋‹ต๋‹ˆ๋‹ค.

useEffect(() => {
    console.log(name);
  }, [name]); //name์˜ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์„๊ฒฝ์šฐ render

3. ๋’ท ์ •๋ฆฌํ•˜๊ธฐ(componentWillUnmount)

๋งŒ์•ฝ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋˜๊ธฐ ์ „์ด๋‚˜, ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ง์ „์— ์–ด๋– ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด useEffect ์—์„œ ๋’ท์ •๋ฆฌ(cleanup) ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  });

๋งŒ์•ฝ์—, ์˜ค์ง ์–ธ๋งˆ์šดํŠธ ๋  ๋•Œ๋งŒ ๋’ท์ •๋ฆฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์œผ์‹œ๋‹ค๋ฉด useEffect ํ•จ์ˆ˜์˜ ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋น„์–ด์žˆ๋Š” ๋ฐฐ์—ด์„ ๋„ฃ์œผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  }, []);

์—ฌ๋Ÿฌ๊ฐœ์˜ effect ์‚ฌ์šฉ ๊ฐ€๋Šฅ

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
  });
  // ...
}

๐Ÿ”’ Hook์˜ ๊ทœ์น™

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

๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ ํ˜น์€ ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœ โŒ

Why?
๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ๋™์ผํ•œ ์ˆœ์„œ๋กœ Hook์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ

๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ 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;
  });

  // ...
}

// ------------
// ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง
// ------------
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์„ ์“ด๋‹ค๋ฉด?(2๋ฒˆ ํ•ญ๋ชฉ)

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

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

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

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

  // ...
}


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

name !== '' ์กฐ๊ฑด
์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง =>true
๊ทธ๋‹ค์Œ ๋ Œ๋”๋ง์—์„œ ํผ์„ ์ดˆ๊ธฐํ™”๋จ => false

Hook์˜ ์ˆœ์„œ๊ฐ€ ํ•˜๋‚˜์”ฉ ๋ฐ€๋ฆฌ๋Š” ๋ฒ„๊ทธ ๋ฐœ์ƒ

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

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

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

Hook์„ ์ผ๋ฐ˜์ ์ธ JavaScript ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœ โŒ

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

๐Ÿ’ฌ ์ž์‹ ๋งŒ์˜ Hook ๋งŒ๋“ค๊ธฐ

์ž์‹ ๋งŒ์˜ Hook์„ ๋งŒ๋“ค๋ฉด ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ๋ฝ‘์•„๋‚ด์–ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ‘์˜ ์‚ฌ์ง„์—์„œ ๋‘ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐ™์€ ๋กœ์ง ์‚ฌ์šฉ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ Hook ์ถ”์ถœํ•˜๊ธฐ

๋‘ ๊ฐœ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์—์„œ ๊ฐ™์€ ๋กœ์ง์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์™€ Hook ๋˜ํ•œ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

์‚ฌ์šฉ์ž ์ •์˜ Hook์€ ์ด๋ฆ„์ด use๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜


import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  // friendID๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๊ณ  ์˜จ๋ผ์ธ ์ƒํƒœ์˜ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}


๊ณตํ†ต๋ถ€๋ถ„์„ useFriendStatus() ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋‹ค.

์ด๋•Œ ์ฃผ์˜์‚ฌํ•ญ๋“ค์€

1. ์‚ฌ์šฉ์ž ์ •์˜ Hook์˜ ์ด๋ฆ„์€ โ€œuseโ€๋กœ ์‹œ์ž‘๋˜์–ด์•ผ ํ•œ๋‹ค
Why?
ํŠน์ •ํ•œ ํ•จ์ˆ˜๊ฐ€ ๊ทธ ์•ˆ์—์„œ Hook์„ ํ˜ธ์ถœํ•˜๋Š”์ง€๋ฅผ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— use ์‚ฌ์šฉ ์•ˆํ• ์‹œ, Hook ๊ทœ์น™์˜ ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ์ž๋™์œผ๋กœ ์ฒดํฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

2. ๊ฐ™์€ Hook์„ ์‚ฌ์šฉํ•˜๋Š” ๋‘ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋Š” state๋ฅผ ๊ณต์œ  โŒ
Why?
์ƒํƒœ ๊ด€๋ จ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์ง€๋งŒ ์‚ฌ์šฉ์ž Hook์„ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ๊ทธ ์•ˆ์˜ state์™€ effect๋Š” ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ด๋‹ค.

๐Ÿ“‹ Hook ์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ ๋ชจ์Œ

Q1:Class๋กœ ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ์ค‘์— Hook์œผ๋กœ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด ๋ฌด์—‡์ธ๊ฐ€?

A1:Hook์€ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๊ธฐ๋Šฅ์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•˜๊ณ  ํ‘œํ˜„์ ์ธ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์„ ์ œ๊ณต(์ž์‹ ๋งŒ์˜ Hook ๋งŒ๋“ค๊ธฐ)

Q2.์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ Hook์— ์–ด๋–ป๊ฒŒ ๋Œ€์‘ํ•ฉ๋‹ˆ๊นŒ?

A2:

  • constructor: useState ํ˜ธ์ถœ์—์„œ state๋ฅผ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ์ดˆ๊ธฐ state๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์ด ๋น„์‹ธ๋ฉด useState์— ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});
  • getDerivedStateFromProps: ๋Œ€์‹  ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ ์—…๋ฐ์ดํŠธ ์˜ˆ์•ฝ.
  • shouldComponentUpdate: React.memo๋ฅผ ์ฐธ์กฐํ•ด์ฃผ์„ธ์š”.
  • render: ์ด๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋ณธ์ฒด ์ž์ฒด์ž…๋‹ˆ๋‹ค.
  • componentDidMount, componentDidUpdate, componentWillUnmount:
    useEffect Hook์€ ์ด๋“ค์˜ ๋ชจ๋“  ์กฐํ•ฉ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • getSnapshotBeforeUpdate, componentDidCatch ๊ทธ๋ฆฌ๊ณ  getDerivedStateFromError: ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ Hook์€ ์—†์ง€๋งŒ, ๊ณง ์ถ”๊ฐ€๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

Q3.ํ•˜๋‚˜ ๋˜๋Š” ์—ฌ๋Ÿฌ state ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

A3: useState()๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ๋ชจ๋“  state๋ฅผ ๋‹จ์ผ ๊ฐ์ฒด์— ๋„ฃ๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Box() {
  const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 });
  // ...
}
--------------------------------------------------------------
 // ...
  useEffect(() => {
    function handleWindowMouseMove(e) {
      // "... state"๋ฅผ spread ํ•˜์—ฌ ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ "์†์‹ค"๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
      setState(state => ({ ...state, left: e.pageX, top: e.pageY }));
    }
    // ์ฃผ์˜: ์ด ๊ตฌํ˜„์€ ์•ฝ๊ฐ„ ๋‹จ์ˆœํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค
    window.addEventListener('mousemove', handleWindowMouseMove);
    return () => window.removeEventListener('mousemove', handleWindowMouseMove);
  }, []);
  // ...
profile
๋ฐฑ์•ค๋“œ๊ฐœ๋ฐœ ๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€