[TIL] 220325

dev·2022년 3ė›” 25ėž
1

TIL

ëŠĐ록 ëģīęļ°
203/204
post-thumbnail

📝 ė˜Ī늘 한 ęēƒ

  1. react effects

📚 ë°°ėšī ęēƒ

ėƒˆëĄ­ęēŒ ė•ŒęēŒ ëœ ë‚īėšĐėī거나 ėīí•ī하ęļ° ė–īë Īė› ë˜ ëķ€ëķ„ë§Œ ė •ëĶŽ

1. Using the Effect Hook

ė―”ë“œëŠ” Using the Effect Hook 페ėīė§€ ė°ļęģ 
2) & 3)ė€ [TIL] 220125도 í•Ļęŧ˜ ė°ļęģ 

1) side effect란?

프로ę·ļëž˜ë°ė—ė„œ side effect(또는 effect)란, ė–īë–Ī í•Ļėˆ˜ę°€ í•Ļ눘 ė™ļëķ€ė˜ ė •ëģī뙀 똁í–Ĩė„ ėĢžęģ  ë°›ëŠ” ėžė„ 말한ë‹Ī.
똈ëĨž ë“Īė–ī, Reactė—ė„œ í•Ļ눘 ėŧī폮넌íŠļ는 때론 UI뗐 ę·ļë ĪėĪ„ 데ėī터ëĨž ė™ļëķ€ė—ė„œ 가ė ļė™€ė•ž 할 ėˆ˜ë„ ėžˆëŠ”ë°, ėī ęē―뚰 ė„œëē„뙀 ęĩëĨ˜í•˜ëŠ” ë„ĪíŠļė›ŒíŽ ėš”ėē­ė„ side effect띞ęģ  í•  눘 ėžˆë‹Ī.

ę·ļ런데 ėī럮한 ėš”ėē­ė€ ėē˜ėŒ 한 ëēˆë§Œ í•„ėš”í•˜ęģ  í•Ļ눘 ėŧī폮넌íŠļ가 렌더링 될 때마ë‹Ī ėš”ėē­í•  í•„ėš”ëŠ” ė—†ëŠ” ęē―ėš°ę°€ 많ë‹Ī.
useEffect()ëĨž ė‚ŽėšĐ하ëĐī í•Ļ눘 ėŧī폮넌íŠļė—ė„œ ėī ę°™ė€ side effectëĨž íšĻėœĻė ėœžëĄœ ėˆ˜í–‰í•  눘 ėžˆë‹Ī.

데ėī터 가ė ļė˜Īęļ° ė™ļė—ë„ ęĩŽë…(subscription) ė„Īė •í•˜ ę·ļëĶŽęģ  ėœ„ė—ė„œ ė‚īíŽīëģļ ėˆ˜ë™ėœžëĄœ React ėŧī폮넌íŠļė˜ DOM ėˆ˜ė •í•˜ęļ° ë˜í•œ side effect뗐 í•īë‹đ한ë‹Ī.

2) ė •ëĶŽ(clean-up)ëĨž ėīėšĐí•˜ė§€ ė•ŠëŠ” effects

side effect ėĪ‘ė—ė„œ ë„ĪíŠļė›ŒíŽ ėš”ėē­, DOM ėˆ˜ë™ ėĄ°ėž‘, 로ęđ… ë“ąė€ ė •ëĶŽ(clean-up)가 í•„ėš”ė—†ë‹Ī.

  • React class ė‚ŽėšĐ

render ëĐ”ė„œë“œ ę·ļ ėžėēī는 side effectëĨž ë°œėƒė‹œí‚Īė§€ ė•ŠëŠ”ë‹Ī.
side effect는 React가 DOMė„ ė—…ë°ėīíŠļ 한 í›„ė— ėˆ˜í–‰ëœë‹Ī.
React classė—ė„œ side effect는 componentDidMount뙀 componentDidUpdateė—ė„œ ėˆ˜í–‰ëœë‹Ī.

React class ė•ˆė—ė„œ 2ę°œė˜ ėƒëŠ…ėĢžęļ° ëĐ”ė„œë“œė— ę°™ė€ ė―”ë“œę°€ 반ëģĩ되는데, ėīëĨž ę°œė„ í•  ë°Đëē•ėī ė—†ęļ° ë•ŒëŽļ뗐 ėĪ‘ëģĩ ė―”ë“œëĨž ė‚ŽėšĐí•īė•ž 한ë‹Ī.

  • useEffect() ė‚ŽėšĐ

React classė—ė„œė™€ ë§ˆė°Žę°€ė§€ëĄœ side effect가 ėˆ˜í–‰ë˜ëŠ” ė‹œė ė— ėīëŊļ DOMėī ė—…ë°ėīíŠļ ë˜ė—ˆėŒė„ ëģīėžĨ한ë‹Ī.
useEffect()가 ėēŦ ëēˆė§ļ ėļėžëĄœ 받는 í•Ļ눘ëĨž 'effect'띞ęģ  ëķ€ëĨļë‹Ī.
React는 ėŧī폮넌íŠļ 렌더링 ė‹œ ėī í•Ļ눘ëĨž ęļ°ė–ĩ했ë‹Ī가 DOM ė—…ë°ėīíŠļęđŒė§€ 끝난 í›„ė— ėī í•Ļ눘ëĨž ëķˆëŸŽë‚ļë‹Ī.

effect í•Ļėˆ˜ëŠ” (두 ëēˆė§ļ ėļėž ė—†ėī ė‚ŽėšĐ하ëĐī) ęļ°ëģļė ėœžëĄœ ėēŦ ëēˆė§ļ ë Œë”ë§ė„ ëđ„ëĄŊí•ī ėīí›„ė˜ ëŠĻ든 ėŧī폮넌íŠļ ė—…ë°ėīíŠļ ė‹œė— ė‹Ī행된ë‹Ī.
React classė—ė„œė™€ 닮ëĶŽ ėīëĨž 나눠 ėž‘ė„ąí•˜ė§€ ė•Šė•„ë„ 되ęļ° ë•ŒëŽļ뗐 ėĪ‘ëģĩ ė―”ë“œëĨž ė‚ŽėšĐ할 í•„ėš”ę°€ ė—†ë‹Ī.

3) ė •ëĶŽ(clean-up)ëĨž ėīėšĐ하는 effects

side effect ėĪ‘ė—ė„œ ęĩŽë…ė„ ė„Īė •í•˜ëŠ” ęēƒ(ex.ėīëēĪíŠļ ęĩŽë… 등)ė€ ëДëŠĻëĶŽ ëˆ„ėˆ˜ëĨž ë°Đė§€í•˜ęļ° ėœ„í•ī ė •ëĶŽ(clean-up)ëĨž í•„ėš”ëĄœ 한ë‹Ī.

  • React class ė‚ŽėšĐ

React classė—ė„œ side effect는 componentDidMount뙀 componentDidUpdateė—ė„œ ėˆ˜í–‰ë˜ęģ , componentWillUnmountė—ė„œ ė •ëĶŽ(clean-up)된ë‹Ī.

ę·ļ런데 ėī뙀 ę°™ė€ ėƒëŠ…ėĢžęļ° ëĐ”ė„œë“œë“Īė€ ę°œë…ėƒ ë˜‘ę°™ė€ effect ė―”ë“œëĨž 氀맀ęģ  ėžˆėŒė—ë„ React classė—ė„œëŠ” ë§Īëēˆ ėĪ‘ëģĩėœžëĄœ ėž‘ė„ąí•īė•žë§Œ 한ë‹Ī.

  • useEffect() ė‚ŽėšĐ

useEffect()ė˜ ėēŦ ëēˆė§ļ ėļėžėļ effect í•Ļėˆ˜ę°€ cleanup í•Ļ눘ëĨž return 하도록 ėž‘ė„ąí•˜ëĐī ėŧī폮넌íŠļ가 마ėšīíŠļ í•īė œë˜ė–ī ė •ëĶŽę°€ í•„ėš”í•  때 cleanup í•Ļėˆ˜ę°€ ė‹Ī행된ë‹Ī.
cleanup í•Ļėˆ˜ëĄœëŠ” ėœ ëŠ…í•Ļėˆ˜ë“  ėĩ멅í•Ļėˆ˜ë“  화ė‚ī표 í•Ļėˆ˜ë“  냁ęī€ė—†ë‹Ī.


2. Hooks API Reference

1) Hook ėžėĢž ëŽŧ는 마ëŽļ

(1) ėĒ…ė†ė„ą ëŠĐëĄė—ė„œ í•Ļ눘 ėŧī폮넌íŠļëĨž ėƒëžĩ하는 ęēƒėī ė•ˆė „í•Đ니ęđŒ?

  • í•Ļ눘 ėŧī폮넌íŠļ (또는 í•Ļ눘 ėŧī폮넌íŠļ가 í˜ļėķœí•˜ëŠ” í•Ļ눘 ėŧī폮넌íŠļ)가 props, state 또는 íŒŒėƒëœ ę°’ė„ ė°ļėĄ°í•˜ė§€ ė•ŠëŠ” ęē―ėš°ė—ëŠ”

    ėĒ…ė†ė„ą ëŠĐëĄė—ė„œ í•Ļ눘 ėŧī폮넌íŠļëĨž ėƒëžĩí•ī도 ė•ˆė „í•˜ë‹Ī.

function Example() {
  // ~ëĨž ė°ļėĄ°í•˜ė§€ ė•ŠëŠ” í•Ļ눘 ėŧī폮넌íŠļ는 effect ė™ļëķ€ė— ė„ ė–ļí•ī도 ok
  function doSomething() {
    console.log('hello');
  }

  useEffect(() => {
    doSomething();
  }, []); // ėĒ…ė†ė„ą ëŠĐëĄė—ė„œ í•Ļ눘 ėŧī폮넌íŠļ ėƒëžĩ ok
}
function Example() {
  useEffect(() => {
    // ~ëĨž ė°ļėĄ°í•˜ė§€ ė•ŠëŠ” í•Ļ눘 ėŧī폮넌íŠļ는 effect ë‚īëķ€ė— ė„ ė–ļí•ī도 ok
    function doSomething() {
      console.log('hello');
    }

    doSomething();
  }, []); // ėĒ…ė†ė„ą ëŠĐëĄė—ė„œ í•Ļ눘 ėŧī폮넌íŠļ ėƒëžĩ ok
}
  • í•Ļ눘 ėŧī폮넌íŠļ (또는 í•Ļ눘 ėŧī폮넌íŠļ가 í˜ļėķœí•˜ëŠ” í•Ļ눘 ėŧī폮넌íŠļ)가 props, state 또는 íŒŒėƒëœ ę°’ė„ ė°ļėĄ°í•˜ëŠ” ęē―ėš°ė—ëŠ”

    • ę·ļ í•Ļ눘 ėŧī폮넌íŠļëĨž effect ë‚īëķ€ė— ė„ ė–ļ하ęģ  ė°ļėĄ°í•˜ëŠ” props 또는 stateëĨž ėĒ…ė†ė„ą ë°°ė—ī뗐 ėķ”ę°€í•īė•ž 한ë‹Ī.

    • ë§Œė•― ė–īë–Ī ėīėœ ëĄœ í•Ļ눘 ėŧī폮넌íŠļëĨž effect ë‚īëķ€ëĄœ ėī동할 눘 ė—†ęģ  effect ė™ļëķ€ė— 두ė–īė•ž 한ë‹ĪëĐī, useEffect() ėĒ…ė†ė„ą ëŠĐëĄė— í•īë‹đ í•Ļ눘 ėŧī폮넌íŠļëĨž ėķ”ę°€í•˜ë˜(ėƒëžĩ X), effect ė™ļëķ€ė— ėœ„ėđ˜í•œ ę·ļęēƒė˜ ė •ė˜ ëķ€ëķ„ė€ useCallback()ėœžëĄœ 감ė‹ļė•ž 한ë‹Ī.

function ProductPage({ productId }) {
  // effect ė™ļëķ€ė— ėœ„ėđ˜í•œ í•Ļ눘 ėŧī폮넌íŠļė˜ ė •ė˜ ëķ€ëķ„ė„ useCallback()ėœžëĄœ ę°ė‹žë‹Ī
  // 'propsëĨž ė°ļėĄ°í•˜ëŠ”' í•Ļ눘 ėŧī폮넌íŠļ가 effect 'ė™ļëķ€'뗐 ėœ„ėđ˜í•ī ėžˆėœžëŊ€ëĄœ
  const fetchProduct = useCallback(() => {
    // ...
  }, [productId]);

  return <ProductDetails fetchProduct={fetchProduct} />;
}

function ProductDetails({ fetchProduct }) {
  useEffect(() => {
    fetchProduct();
  }, [fetchProduct]); // í•īë‹đ í•Ļ눘 ėŧī폮넌íŠļëĨž useEffect() ėĒ…ė†ė„ą ëŠĐëĄė—ė„œ ėƒëžĩí•īė„  ė•ˆëœë‹Ī
  // ...
}

ėī렇ęēŒ í•˜ëĐī ProductPageė—ė„œ productId propėī ëģ€ęē―되ëĐī
ProductDetails ėŧī폮넌íŠļė—ė„œ ėžë™ėœžëĄœ ë‹Īė‹œ 가ė ļė˜Īęļ°ę°€ íŠļëĶŽęą° 된ë‹Ī.(fetchProduct í•Ļ눘 ė‹Ī행)

(2) effect ėĒ…ė†ė„ąėī 너ëŽī ėžėĢž ëģ€ęē―되ëĐī ė–īë–ŧęēŒ í•īė•ž í•Đ니ęđŒ?

function Counter() {
  const [count, setCount] = useState(0);

  // console.log(count); // ėē˜ėŒ 렌더링 ė‹œ 0, ę·ļ ėī후로 ęģ„ė† 1
  
  useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1); // effect가 count state뗐 ė˜ėĄīí•Ļė—ë„ ëķˆęĩŽí•˜ęģ 
    }, 1000);

    return () => clearInterval(id);
  }, []); // ėĒ…ė†ė„ą ëŠĐëĄė— countëĨž ėƒëžĩ했ë‹Ī => ëē„ę·ļ ❗

  return <h1>{count}</h1>;
}

ReactDOM.render(<Counter />, document.getElementById("root"));

ė™ļëķ€ í•Ļ눘ėļ Counter í•Ļėˆ˜ė˜ count state는 ë‚īëķ€ í•Ļ눘ėļ setIntervalė˜ ė―œë°ą í•Ļėˆ˜ė—ė„œ ė°ļėĄ°í•˜ęģ  ėžˆęļ° ë•ŒëŽļ뗐 íīëĄœė €ëĨž í˜•ė„ąí•˜ęēŒ ëœë‹Ī.
ęē°ęĩ­ 1ėīˆę°€ ė§€ë‚  때마ë‹Ī setCount(count + 1) ė‹Ī행 ė‹œ íīëĄœė €ëĄœ ėļí•ī ë§Īëēˆ count stateė˜ ėīˆęđƒę°’ 0ė„ 가ė ļė˜ĪęēŒ ë˜ė–ī ęē°ęģžė ėœžëĄœ countė˜ ę°’ė„ 1로 바ęŋ€ ëŋėīęģ , 멇 ėīˆę°€ ė§€ë‚˜ë”ëžë„ countė˜ 값ėī ę·ļ ėīėƒė„ ėīˆęģží•  ėˆ˜ëŠ” ė—†ë‹Ī.

ëē„ę·ļëĨž í•īęē°í•˜ęļ° ėœ„í•ī ėĒ…ė†ė„ą ëŠĐëĄė— count stateëĨž ėķ”가할 눘 ėžˆë‹Ī.
ę·ļ런데 ę·ļ렇ęēŒ ë˜ëĐī count stateė˜ 값ėī ë§Īėīˆë§ˆë‹Ī ëģ€í•˜ęļ°ëŠ” í•˜ė§€ë§Œ, ėī는 ė‚Žė‹Ī ė œëŒ€ëĄœ ė―”ë“œëĨž ėž‘ė„ąí–ˆë‹ĪëĐī setIntervalė„ 한 ëēˆë§Œ í˜ļėķœí•˜ëĐī 되는 ęēƒė„, ë§Īėīˆë§ˆë‹Ī count state가 ë°”ë€œė— 따띾 setIntervalė„ ë‹Īė‹œ í˜ļėķœí•˜ęēŒ ë˜ė–ī ë°”ëžŒė§í•˜ė§€ ė•Šë‹Ī.

가ėžĨ ėĩœė„ ė˜ ë°Đëē•ė€ setState í•Ļėˆ˜ė˜ ėļėžëĄœ 'ė―œë°ą í•Ļ눘'ëĨž ë„Ģė–īėĢžëŠ” ęēƒėīë‹Ī.

function Counter() {
  const [count, setCount] = useState(0);

  // console.log(count); // 0, 1, 2, 3... ė •ėƒė ėœžëĄœ ė—…ë°ėīíŠļ가 된ë‹Ī
  
  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1); // 📌  effect가 count state뗐 ė˜ėĄī X, ėīė „ stateëĨž ë°”íƒ•ėœžëĄœ ėƒˆëĄœėšī stateëĨž 도ėķœ
    }, 1000);

    return () => clearInterval(id);
  }, []); // ėĒ…ė†ė„ą ëŠĐëĄė— count ėƒëžĩ => setIntervalė€ ėē˜ėŒ 렌더링 ė‹œ 1ëēˆë§Œ í˜ļėķœëĻ

  return <h1>{count}</h1>;
}

ReactDOM.render(<Counter />, document.getElementById("root"));

2) useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

useReducerė˜ ėēŦ ëēˆė§ļ ėļėžëŠ” (state, action) => newStateė˜ 형태ëĨž ę°€ė§€ëŠ” reducer í•Ļ눘ėīë‹Ī.

ėī때 reducer í•Ļėˆ˜ė˜ 두 ëēˆė§ļ ėļėžėļ actionė€ ė—…ë°ėīíŠļëĨž ėœ„í•œ ė •ëģīëĨž ę°€ė§€ëŠ” 객ėēīėīë‹Ī.
dispatch는 ė•Ąė…˜ė„ ë°œėƒė‹œí‚Ī는 í•Ļėˆ˜ëĄœėĻ, reducer í•Ļėˆ˜ëŠ” dispatch í•Ļėˆ˜ę°€ ë°œėƒė‹œí‚Ļ ė•Ąė…˜ė— 따띾 stateëĨž 반환한ë‹Ī.
reducer í•Ļėˆ˜ę°€ 반환하는 ėƒˆëĄœėšī state가 ęģ§ ėŧī폮넌íŠļė—ė„œ ė‚ŽėšĐ될 state가 된ë‹Ī.

useReducerė˜ 두 ëēˆė§ļ ėļėžëŠ” stateė˜ ėīˆęđƒę°’ė„ 받는ë‹Ī.

useReducerė˜ ė„ļ ëēˆė§ļ ėļėžëŠ” ėīˆęđƒę°’ė„ ė„Īė •í•˜ëŠ” í•Ļ눘ëĨž 받는ë‹Ī.
ėī는 나ėΑ뗐 stateëĨž ėžŽė„Īė • 하는 데도 ė‚ŽėšĐ할 눘 ėžˆë‹Ī.

function init(initialCount) {
  return {count: initialCount};
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

3) useEffect

(1) effect 타ėī밍

componentDidMount뙀 componentDidUpdateė™€ëŠ” 닮ëĶŽ useEffect()로 ė „ë‹Žëœ í•Ļ눘, ė͉ effect í•Ļėˆ˜ëŠ” 맀뗰 ėīëēĪíŠļ ë™ė•ˆė— 레ėīė•„ė›ƒ ë°°ėđ˜ė™€ ę·ļëĶŽęļ°ëĨž 뙄ëĢŒí•œ í›„ė— ë°œėƒí•œë‹Ī.
ėī는 ęĩŽë…ėī나 ėīëēĪíŠļ í•ļë“Ī럮 ė„Īė • ë“ąė˜ side effect가 ëļŒëžėš°ė €ė—ė„œ 화ëĐīė„ ė—…ë°ėīíŠļ하는 ęēƒė„ ė°Ļë‹Ļí•īė„œëŠ” ė•ˆ 되ëŊ€ëĄœ 대ëķ€ëķ„ė˜ ęē―뚰 ë°”ëžŒė§í•˜ë‹Ī.

ę·ļ럮나, ė‚ŽėšĐėžė—ęēŒ ë…ļėķœë˜ëŠ” DOM ëģ€ęē―ęģž ę°™ė€ side effect는 화ëĐīė˜ ė—…ë°ėīíŠļ가 끝나ęļ° ė „ė— 동ęļ°í™”ę°€ 뙄ëĢŒë˜ė–īė•ž 한ë‹Ī.
ėī럮한 side effectëĨž ėœ„í•ī useLayoutEffect()ëĨž ė‚ŽėšĐ할 눘 ėžˆë‹Ī.

4) useCallback

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

useCallbackė€ ëДëŠĻėī렜ėīė…˜ëœ ė―œë°ąė„ 반환한ë‹Ī.

ėēŦ ëēˆė§ļ ėļėžëĄœëŠ” ė―œë°ą í•Ļ눘ëĨž, 두 ëēˆė§ļ ėļėžëĄœëŠ” ėĒ…ė†ė„ą ëŠĐ록(ė˜ėĄīė„ą ę°’ė˜ ë°°ė—ī)ė„ 받는ë‹Ī.

ëĶŽë Œë”ë§ ė‹œė— ėĒ…ė†ė„ą ëŠĐ록ėī ëģ€ęē―ë˜ė§€ ė•ŠëŠ” 한 ëДëŠĻėī렜ėīė…˜ëœ ė―œë°ą 또한 ëģ€ęē―ë˜ė§€ ė•ŠëŠ”ë‹Ī.

ė°ļėĄ°ė˜ ë™ėžė„ąė— ė˜ėĄī렁ėļ ėĩœė í™”된 ėžė‹ ėŧī폮넌íŠļ뗐 ė―œë°ąė„ ė „ë‹Ží•  때 뜠ėšĐ하ë‹Ī. ( ė—Žęļ° ė°ļęģ  )


âœĻ ë‚īėž 할 ęēƒ

  1. react data-flow
profile
dev log

0ę°œė˜ 댓ęļ€