DarrenKwonDev 2020. 3. 21. 05:08

페이스북 공식 문서에 따르면 useEffect를

리액트의 class 생명주기 메서드에 친숙하다면, useEffect Hook을 componentDidMount와 componentDidUpdate, componentWillUnmount가 합쳐진 것으로 생각해도 좋습니다.

라고 한다. 결국 각 라이프 사이클 단계 중 최종적으로 실행되는 것이다. 어쨌거나 render() 이후에 실행되면서 동시에 매번 어떤 동작이 일어날 때마다 작동한다.

 

useEffect는 렌더링 이후에 매번 수행되는 걸까요? 네, 기본적으로 첫번째 렌더링 이후의 모든 업데이트에서 수행됩니다

 

🚗 Component Lifecycle

Mounting : constructor(), render(), componentDidMount()
Updating : render(), componentDidUpdate()
Unmounting : componentWillUnmount()

 

 

useEffect는 2개의 인자를 받는다. 하나는 작동할 함수, 다른 하나는 dependencies이다. 설명에 따르면 deps가 있다면,  effect will only activate if the values in the list change. 라고 한다.

 

명령창을 읽는 버릇을 들이자! 제발!

 

간단하게 useEffect를 사용해보았다. useEffect(callback, [state 인자]). 여기서는 deps를 count만 주었기 때문에 count가 바뀌는 상황에서만 (변함이 없다면 작동하지 않습니다) useEffect가 작동하게 될 것이다.

import React, { useState, useEffect } from "react";

const App = () => {
  const [count, setCount] = useState(0);
  const [testcount, setTestCount] = useState(0);

  useEffect(() => {
    return console.log("hello");
  }, [count]);

  return (
    <>
      <div>count : {count}</div>
      <div>testcount : {testcount}</div>
      <button onClick={() => setCount(count + 1)}>Plus Count</button>
      <button onClick={() => setTestCount(testcount + 1)}>
        Plus testCount
      </button>
    </>
  );
};

export default App;

 

페이스북에서도 비슷한 예를 공식 문서에서 보여주었습니다.

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.

 

추가적으로 state를 추가하고 싶다면 [count, count2, count3] 이런 식으로 배열로 넘겨주면 됩니다.

 

 

Using the Effect Hook – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

만약 componentDidMount()에만 작동하게 하고 싶다면 (최초로 렌더링된 후 1번만 작동) 두 번째 인자에 빈 배열을 할당하면 된다. useEffect(callback, [])

 

빈 객체를 deps로 줄 때 알아둬야 할 속성이, 만약 return 값이 있다면 해당 return은 componentWillUnmount에서 반환(혹은 실행)  될 것이다. 즉, 언마운팅되는 단계의 마지막에서야 return 값이 실행된다는 것이다.

 

빈 객체가 아니라 아무 값도 주지 않는다면? 당연히 매번 실행된다.

 

아래의 useEffect는 빈 객체가 deps이기 때문에 if문이 componentDidMount때 한 번 실행되고 componentWillUnmount때 리턴 문이 실행되면서 이벤트를 제거(CleanUp)합니다. 빈 객체를 deps로 주지 않으면 매번 렌더 때마다 이벤트를 추가하는 동작을 해야 할텐데 이건 메모리 낭비를 야기한다.

useEffect(() => {
  if (element.current) {
    element.current.addEventListener("click", onClick);
  }
  return () => {
    if (element.current) {
      element.current.removeEventListener("click", onClick);
    }
  };
}, []);