[React.js] React Hooks - useEffect⭐

이예빈·2022년 4월 29일
0

Hooks은 React 16.8버전에 새로 추가된 것으로 class를 사용하지 않고도
state와 다른 React의 기능을 지원합니다.

( 원래 React이전 버전에서는 class컴포넌트만이 state와 lifecycle메서드를 사용할 수 있었습니다. )

useEffect⭐

  • useEffect는 컴포넌트가 Mount(화면에 첫 렌더링)되었을 때,Update(다시 렌더링)되었을 때, Unmount(화면에서 사라질 때) 특정 기능을 수행할 수 있게 합니다.

  • 특정기능을 수행하는 함수를 'effect'라 부르고 useEffect의 첫번째 인자로 들어갑니다.

  • useEffect의 형태는 크게 다음처럼 나눌 수 있으며, 두번째 인자는 optional합니다.

    1. useEffect(() => { //수행할 특정 기능..});

      => rendering이 될때 마다 effect가 실행됨. ( Mount + Update )

    2. useEffect(() => { //수행할 특정 기능..},[value]);

      => 두번째 인자가 [value]인 경우 :
      최초로 rendering이 되었을 때 + value값이 변경되었을 때 effect가 실행됨.
      (Mount + [value] Update )

      => 두번째 인자rk 빈배열([ ])인 경우 :
      최초로 rendering 되었을 때 딱 한번만 effect실행됨.

  • Clean-up이 필요한 effect의 경우

    • effect가 렌더링 이후에 실행되었다가 컴포넌트가 unmount될 때 실행되던 effect를 정리해줘야하는 경우가 있다.

    • 예를 들어 useEffect에 타이머를 설정하는 effect 혹은
      특정 이벤트 리스너를 등록하는 effect가 있었다면 해당 컴포넌트가 보이지 않게 되었을 땐
      더이상 실행될 필요가 없으므로 effect를 해제하는 작업이 필요하다.

    • 이런 경우 effect함수에서 clean-up하는 function을 리턴해주면 React가 알아서 해당 컴포넌트가 unMount될때 effect에서 리턴된 function을 실행해서 정리되도록 한다.

  • 따라서, useEffect의 첫번째 인자로 들어가는 effect는 크게 2가지로 나뉜다.

    • clean-up이 필요한 effect : function을 리턴하여 clean-up❗
    • clean-up이 필요없는 effect : 어떤 것도 반환하지 않음.

side effect

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

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

  // componentDidMount, componentDidUpdate와 같은 방식으로
  useEffect(() => {
    // 브라우저 API를 이용하여 문서 타이틀을 업데이트합니다.
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Effect Hook을 사용하면 function 컴포넌트에서 side effect을 수행할 수 있습니다.

🥕 side effect 이란?
위 예제의 useEffect()안의 함수를 보면
document의 title을 count횟수가 포함된 문장으로 표현되도록 하고 있습니다.
이처럼 데이터 가져오기, 구독 설정하기, 수동으로 React 컴포넌트의 DOM 수정하기 등
이런 모든 기능(operations)을 side effect (또는 effect)라고 부릅니다.

Tip ❗
React의 class Lifecycle 메서드에 익숙하다면,
useEffect Hook을 componentDidMountcomponentDidUpdate, componentWillUnmout
합쳐진 것으로 생각해도 괜찮습니다.

즉, 쉽게말해 컴포넌트가 마운트 되었을 때,
컴포넌트가 업데이트 되었을 때,컴포넌트가 언마운트될 때
실행하고자 하는 기능이 있다면 function컴포넌트에서는 useEffect을 사용하면 됩니다.

Rect컴포넌트엔 일반적으로 2종류의 side effects가 있습니다.

  • clean-up이 필요하지 않은 것
  • clean-up이 필요한 것

이 둘을 어떻게 구분하면 좋을지 알아보겠습니다.

clean-up이 필요없는 Effects

  • 네트워크 request
  • DOM 수동동작
  • Logging
    ..etc

이러한 예들은 "clean-up이 필요없는 경우들" 입니다.
얘네들은 실행 이후 신경 쓸 것이 없기 때문입니다.

class컴포넌트와 hook이 이러한 clean-up이 필요없는 side effects를 어떻게 다르게 구현하는지 비교해봅시다.

Class를 사용하는 예

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

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

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

React의 class컴포넌트에서 render메서드 자체는
side effect를 일으키진 않습니다.
아직은 이른 시기로 일반적으로는 effects를 실행시키고자 하는 때는
React가 DOM을 업데이트 한 이후입니다.

class컴포넌트에서 side effect를 componentDidMountcomponentDidUpdate에 두는 것이 바로 이때문입니다.

-> 즉, render실행되어 컴포넌트가 DOM에 최초로 등록되었을 때와 DOM이 수정되었을 때
실행시키고 싶은 side effect이 있으면
componentDidMountcomponentDidUpdate을 사용해서 구현한다는 말!

위 예시 코드에서
두 개의 생명주기 메서드 안에
같은 코드가 중복되는 것을 눈여겨 봅시다.

이는 컴포넌트가 이제 막 마운트 된 단계인지 아니면 업데이트 되는 것인지에 상관없이
같은 side effect을 수행해야 하기 때문입니다.

개념적으로 렌더링 이후에 항상 같은 코드가 실행되길 바라는 것이죠.

하지만, class컴포넌트는 이런 메서드가 구현되어있지 않아서
위처럼 중복되게 코드를 작성할 수밖에 없습니다.

이제 useEffect로 같은 기능을 어떻게 구현하는지 살펴보겠습니다.

Hook을 사용하는 예

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  • useEffect가 하는 일은 무엇일까?

    • useEffect를 이용하여 우리는 컴포넌트가 rendering된 이후에 어떤 일을 수행해야하는지 알려줄 수 있습니다.
    • React는 우리가 넘긴 effect함수를 기억해두었다가 DOM 업데이트를 수행한 이후 불러낼 것입니다.
  • useEffect를 컴포넌트 안에서 불러야 하는 이유는?

    • useEffect를 컴포넌트 내부에 둠으로써 count state변수 (또는 prop에도) 접근할 수 있게 되기 때문입니다.
  • useEffect는 렌더링 이후에 매번 수행되는 걸까?
    • 기본적으로는 첫번째 렌더링과 이후 모든 업데이트에서 수행됩니다.
    • 뒤에서 얘기하겠지만 useEffect의 두번째 인자로 어떤것을 넣느냐에 따라 조정도 가능합니다.

clean-up이 필요한 Effects

위에서 정리(clean-up)가 필요하지 않은 side effect를 보았지만,
정리(clean-up)가 필요한 effect도 있습니다.

  • App.jsx
import React, { useState, useEffect } from 'react';
import Timer  from './component/Timer';

function App() {
  const [showTimer,setShoTimer] = useState(false);
  
  const handleToggleClick = () => {
  	setShowTimer(!showTimer);
  };
  
  return(
    <div>
	    {showTimer && <Timer/>}
    	<button onClick={handleToggleClick}>Toggle Timer</button>
    </div>
    );
}

export default App;
  • Timer.jsx
import React, { useEffect } from 'react';

const Timer = (props) => {
  
  //Timer컴포넌트가 처음 렌더링 되었을 때(Mount)만
  // 1초마다 콘솔출력하는 effect를 등록함
  useEffect(() => {
    const timer = setInterval(() => {
     	console.log('타이머 돌아가는 중...')'
    },1000);
    
    //Timer컴포넌트가 unmount되었을 때 정리되도록 function리턴
    return () => {
      clearInterval(timer);
      console.log('타이머가 종료되었습니다.');
    };
  },[]);
  
  return(
    <div>
    	<span>타이머를 시작합니다. 콘솔을 확인하세요!</span>
    </div>
    );
}

export default Timer;

Effects 이용 Tip

  • useEffect Hook을 이용하면 class컴포넌트의 Lifecyle메서드에 따라서가 아니라 "코드가 무엇을 하는지에 따라" 나눌 수 있습니다.
    ( useState처럼 useEffect도 여러번 사용할 수 있습니다. 따라서, 서로 관련있는 것들끼리만 useEffect에 담아둘 수 있습니다.)
  • useEffect두번째 인자로 무엇을 전달하는 가에 따라 effect를 실행시킬 수도 건너뛰게 할 수도 있습니다.
    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [count]);
    • [count]를 두번째 인자로 넘겼다면, React는 count변수의 변화가 있을 때만 effect를 실행합니다.
    • ([]) 빈 배열을 두번째 인자로 넘겼다면, 딱 한번 만 실행합니다. 따라서, effect안의 prop과 state는 최초 실행되었을 때의 값을 계속 가지므로 초기값으로 유지됩니다.

참고
https://ko.reactjs.org/docs/hooks-effect.html
https://reactjs.org/docs/hooks-effect.html
https://www.youtube.com/watch?v=kyodvzc5GHU

0개의 댓글