React 에서 useEffect의 return 호출 조건이 이해가 안됩니다!

이번에 리액트 Hook 기능중에 useEffect를 배웠습니다.

그런데 제가 헷갈리는 게, useEffect에 함수를 정의할때 해당 함수가 return할 때의 코드가 일반적인 class기반 컴포넌트의 Lifecycle에서 componentWillUnmount와 같다고 설명하는데, 실제로 unmount 되지 않고 state가 변경될 때 마다 호출되고 있습니다.

class 기반 컴포넌트에서는 compoenetWillUnmount가 정말 컴포넌트가 렌더링 화면에서 사라질 때 호출되었는데 function 기반 컴포넌트에서 useEffect return이 호출되는 정확한 타이밍이 언제일까요?

제가 하도 이해가 안되서 같은 기능의 컴포넌트를 class방식과 function 방식으로 만들어봤습니다.

먼저 function 기반의 컴포넌트 입니다.

const App = () => {
    const [number, setNumber] = useState(0);
    useEffect(() => {
        console.log('component did mount with useEffect!');
        return () => {
            console.log("component will unmount");
        };
    }, [number]);
    return (
        <div>
            <h2>number is {number}</h2>
                <button
                    onClick={() => {
                        setNumber(number + 1);
                    }}
                >
                Increment
            </button>
        </div>
    );
};

이렇게 하면 버튼을 클릭 할 때마다 number state가 1씩 올라가고

콘솔창에는

component will unmount

component did mount with useEffect!

이렇게 표시가 됩니다. 즉 언마운트 되고 나서 갱신되는 것이 표현됩니다.

그리고 아래는 class 기반으로 만든 컴포넌트 입니다.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };
  }
  componentDidMount() {
    console.log('component did mount');
  }
  componentDidUpdate() {
    console.log('component did update');
  }
  componentWillUnmount() {
    console.log('component will unmount');
  }
  render() {
    const { number } = this.state;
    return (
      <div>
        <h2>number is {number}</h2>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
          }}
        >
        Increment
        </button>
      </div>
    );
  }
}

제 생각에는 같은 기능을 하는 컴포넌트 입니다. 그런데 이 때는 클릭 할 때 마다

component did update

만 표시됩니다. 물론 componentDidUpdate를 없애면 콘솔에는 아무것도 출력되지 않습니다…

긴 글 읽어주셔서 감사합니다… 결론적으로 궁금한 건 useEffect에서 return이 호출되는 타이밍이 정말 컴포넌트가 언마운트 될 때가 맞는지… 그게 궁금하네요… 두 기능의 차이점을 정확히 알고싶어요 ㅠㅠ

1개의 좋아요

[number] 대신에 [] 로 바꾸면 될거에요.

useEffect는 return값은 해당 effect가 더이상 실행할 필요가 없을 때 청소하는 용도입니다.
여기서 더 이상 실행할 필요가 없는 경우는 다음 두가지 입니다.

  1. dependancy(두번째 인자로 넘기는 배열)가 바뀌어서 effect가 달라져야할 때 (이전 effect 청소)
  2. 해당 component가 unmount 될 때

2번에 해당하는 unmount 될 때만 사용하려면 @choipd 님이 말씀하신 것처럼 dependancy가 항상 같도록 []를 넘기면 됩니다.

혹시나해서 몇자 남겨욤(사용자화면기준)…잘못된 부분있으면 댓글주세요…
1. const [number, setNumber] = useState(0);
2. useEffect(() => {

}, [number]);

onClick > 클래스내에 1,2번이 차례로 useState, useEffect 호출될 것입니다.
즉 number이 변경되면 1번 선언조건때문에 App 렌더링> 2번은 number를 바라보고 있다가 직전값과 다르므로 또 App 렌더링…

  • [number] > []로한다면 useEffect는 처음(f5) 화면을 렌더링 될때 한번만 호출. 이후 호출될 일이 없음
  • useEffect 사용목적으로 맞지않습니다. [ ]로처리한다거나 함수호출이 없다면 useEffect 사용 할 필요가 없다는 것입니다.
  • useEffect > return : 함수호출 있고난후 함수처리를 위해 사용되었던 공간을 반환합니다.
    동일한 조건으로 호출될 경우 return 정의가 없으면 가상머신이 알아서 처리합니다.
    브라우져 메모리사용량이 증가, 컴파일 경고하니 내부에 함수호출이 있으면
    return처리 추천.
    * 타입이 선언된 함수는 리턴이 되면 사용했던 공간을 다시 반환합니다.
  1. this.setState({ number: number + 1 });
    이건만 있으니 onClick 할때마다 한번만 렌더링 하겠죠 > componentDidUpdate()만 호출

문서나 기타 강좌들에서 라이프사이클, 후크, 마운트다 뭐다라며 설명들 하고 있지만…
어찌되었건 이러한 함수(클래스)들을 사용하는 딱 하가지 이유는
최초에 반영된 화면이후 다시 반영하게 하기 위함입니다. (화면을 전체를 다시 그릴것이냐 원하는 부분만 다시 렌더링 할 것이냐만 잘 선택적으로…),
*화면에 보일 필요가 없다면 처음부터 사용할 필요가 없겠죠…

다른 언어들도 매우 비슷한 방법(구조, 알고리즘)으로 화면(앱스크린, 브라우져) 처리합니다.
결론 : 변수선언 > 값변경 > 변경된 값을 화면에 반영할 것이냐 아니냐를 처음 정의시 구분하던가
선언후 반영하도록 함수처리 하는것으로 구분 할 수 있을 것입니다.

1개의 좋아요