React hooks image
Part1에서는 Hook을 통해 Class가 아닌 function(함수)만으로 state를 생성하고 갱신하는 방법을 알아보았습니다.

그러나 우리는 그것을 넘어서 state의 라이프 사이클을 다루고 싶습니다. 그것을 위해 우리는 Effect Hook에 대해 알아보겠습니다.

자 우선 기존에 Class를 통해 라이프 사이클을 다루는 방법을 확인해 보겠습니다.

Ex) Class로 라이프 사이클 다루기

import React from "react";

class Example extends React.Component {
  // state를 초기화 시켜주기 위해 constructor를 사용합니다.
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  // componentDidMount는 컴포넌트를 렌더링하고 마운트가 되면 실행됩니다.
  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  // componentDidUpdate는 state가 업데이트가 되고 그 후에 실행됩니다.
  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>
    );
  }
}

위의 코드는 충분히 잘 작동되는 코드입니다. 그러나 좀 길어보이죠 이것을 Hooks를 사용해 만든다면 어떨까요?

  • useEffect

    Hook으로 라이프사이클을 다루기 위해 우리는 useEffect가 필요합니다.
    바로 예제를 통해 알아봅시다.

Ex) useEffect로 componentDidMount 작업하기

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

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

  // useEffect는 첫번째 인자로 callBack함수를 받습니다.
  useEffect(() => {
    // 컴포넌트가 마운트 되고 setTimeout함수를실행합니다.
    setTimeout(() => {
        document.title = `You clicked ${count} times`;
    }, 3000);   
  }, []); <--- 두번째 인자로  배열 넣어주기

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

useEffect함수를 마운트되고 한번만 실행하게 하려면 두번째 인자로 빈 배열을 넣어주세요 그렇지 않으면 state값이 업데이트 될경우 다시 한번 렌더링을 해줍니다.

위의 코드에서 확인해보면 useEffect 함수는 컴포넌트가 마운트 된 이후 setTimeout함수를 실행시켜 3초가 지나면 문서의 타이틀을 교체할겁니다.

이런식으로 우리는 Class에서 사용했던 componentDidMount와 동일한 작업을 할수있습니다.

그렇다면 컴포넌트가 업데이트되고 난후에 작동하는 componentDidUpdate는 어떻게 할수 있을까요?

Ex) useEffect로 componentDidUpdate 작업하기

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

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

  // useEffect는 첫번째 인자로 callBack함수를 받습니다.
  useEffect(() => {
    // 컴포넌트가 업데이트 되고 setTimeout함수를 실행합니다.
    setTimeout(() => {
        document.title = `You clicked ${count} times`;
    }, 3000);   
  }, [count]); <------ 여기 집중!!!!!!!!!

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

위의 코드를 보면 useEffect함수 두번째 인자에 count를 배열안에 넣어주었습니다. 이렇게 하면 useEffect는 count state를 지켜보다가 count가 갱신되면 첫번째 인자로 넣어주었던 함수를 실행하게 됩니다.

이렇게 우리는 Class에서 다루었던 componentDidmount와 같은 동일한 작업을 Hook을통해 할수있습니다.

이제 우리는 마지막으로 componentWillUnmount에 대해 알아보겠습니다.
거의 사용할 일이 없지만 이것을 사용하지 않으면 버그가 발생하는 경우가 있으니 사용하는 습관을 가지는것이 좋습니다.

Ex) useEffect로 componentWillUnmount 작업하기

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

// Scroll을 움직이면 h1의 스타일을 변화해주기 위한 함수.
const useScroll = () => {
  // state를 생성합니다.
  const [state, setState] = useState({
    x: 0,
    y: 0
  });
  // scrll의 값을 가져와 state를 갱신합니다.
  const onScroll = () => {
    setState({ y: window.scrollY, x: window.scrollX });
  };
  useEffect(() => {
    // scroll 이벤트를 만들어줍니다. 스크롤을 움직일때 마다 
    // onScroll 함수가 실행됩니다.
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll); <---- 집중 !!!
  }, []);
  return state;
};

const App = () => {
  const { y } = useScroll();
  return (
    <div style={{ height: "1000vh" }} className="App">
      <h1 style={{ position: " fixed", color: y > 100 ? "red" : "blue" }}>
        Hi
      </h1>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

위의 코드에서 useEffect부분만 가져와서 자세히 살펴보겠습니다.

  useEffect(() => {
    // scroll 이벤트를 만들어줍니다. 스크롤을 움직일때 마다 
    // onScroll 함수가 실행됩니다.
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll); <---- 집중 !!!
  }, []);
  return state;
};

우리는 scroll 이벤트를 만들었습니다. 그런데 만약 어떤 이유로 인해 컴포넌트가 지워진다면 우리는 해당 이벤트를 반드시 지워주어야 합니다.

그렇지 않으면 저 이벤트는 계속 남아있게 되어 원치않은 상황을 만들게 될것입니다. 그때 우리는 한번더 함수를 반환해줍니다.
이것이 바로 Class에서 사용했던 componentWillUnmount처럼 동일한 작업을 해줄겁니다.

여기까지 우리는 기본적인 Effect Hook에 대해서 알아보았습니다.