[TIL] 220325

Lee Syong·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
ëŠĨ동ė ėœžëĄœ ė‚īėž, 행ëģĩ하ęēŒðŸ˜

0개ė˜ 댓ęļ€