useEffect

2023-09-04
ReactHooks

Table of Contents

useEffect가 나오게 된 배경

  • 클래스형 컴포넌트에서 함수형 컴포넌트로 바뀔 때 클래스형 컴포넌트의 강점인 생명주기(라이프사이클)과 상태값 관리를 Hook이란 개념으로 도입하게 되면서 생명주기를 useEffect라는 Hook으로 관리하게 되었습니다.

1. 프로젝트 세팅 React + TS + Vite

$ npm init vite@latest React-UseEffect -- --template react-ts
$ cd React-UseEffect
$ npm i

/src/main.tsx

import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  // <React.StrictMode>
  <App />
  // </React.StrictMode>,
);
  • React StrictMode를 끄고 하겠습니다. 두번 렌더링이 되어 콘솔이 지저분해집니다.

2. useEffect 사용해보기

  • 리액트 생명주기의 큰 틀
    • mount → updating → unmounting

Mount의 개념

  • 컴포넌트가 처음으로 DOM에 추가되는 초기 과정

Updating의 개념

  • 컴포넌트의 상태나 속성이 변경되어 화면을 업데이트해야 할 때 발생하는 과정

/src/App.tsx

import "./App.css";
import { useState } from "react";
import Mount from "./Mount";
import Updating from "./Updating";

function App() {
  const [isMount, setIsMount] = useState<boolean>(false);

  function onClickHandler(event: React.MouseEvent) {
    event.preventDefault();
    setIsMount((prev) => !prev);
  }
  return (
    <main>
      <button onClick={onClickHandler}>{isMount ? "mount" : "render"}</button>
      {isMount ? <Mount /> : <Updating />}
    </main>
  );
}

export default App;
  • isMount가 true면 Mount 컴포넌트 마운트, 아니면 Updating 컴포넌트 마운트가 됩니다.

Mounting & unMounting

  • useEffect로 mounting과 unmounting 주기를 관리하는 방법에 대해서 알아봅니다.

/src/Mount.tsx

import { useEffect } from "react";

const MountUnMount = () => {
  useEffect(() => {
    console.group("Mount");
    console.log("useEffect(() => {},[])");
    console.log("마운트 될 때에 실행");
    console.groupEnd();
    return () => {
      console.group("UnMount");
      console.log("return () => {}");
      console.log("마운트가 해제될 때 실행");
      console.groupEnd();
    };
  }, []);
  return <div>Mount!</div>;
};

export default MountUnMount;
  • mounting입니다. useEffect에 빈 배열을 넣어주면 mounting시에 실행됩니다.
    • mounting이 되면 DOM에 접근할 수 있습니다.
  • unmounting입니다. useEffect에 return과 실행시킬 함수를 할당하면 unmounting시 실행됩니다.
    • unmounting시에 접근할 수 있는 return 함수를 clean-up 함수라고 명명하고 있습니다.

updating

  • useEffect로 updating 주기를 관리하는 방법에 대해서 알아봅니다.

/src/Updating.tsx

import React, { useEffect, useState } from "react";
import UpdateChild from "./UpdateChild";

const Updating = () => {
  const [state, setState] = useState("state");

  useEffect(() => {
    console.group("Updating, 첫 렌더링 시 실행된다.");
    console.log(`useEffect(() => {}, [state])`);
    console.log(`Updating state 값이 업데이트 되었습니다 ::: ` + state);
    console.groupEnd();
    return () => {
      console.log(`return () => {}`);
      console.log(`Updating 컴포넌트가 언마운트 되었습니다 ::: ` + state);
    };
  }, [state]);
  useEffect(() => {
    console.log(`Updating Component re-rendering`);
  });

  function onChangeHandler(event: React.ChangeEvent<HTMLInputElement>) {
    event.preventDefault();
    setState(event.target.value);
  }
  return (
    <div>
      <input type='text' onChange={onChangeHandler} value={state} />
      <div>{state}</div>
      <UpdateChild />
    </div>
  );
};

export default Updating;
  • 처음 실행될 때와 배열 안에 넣은 값이 있으면(useState) 그 값이 변경됨에 따라 updating이 발생합니다.
  • unmount의 동작은 같습니다.
  • 의존성 배열이 없다면 컴포넌트가 updating을 할때마다 호출됩니다.

자식요소 updating

/src/Updating.tsx

import React, { useEffect } from "react";

const UpdateChild = () => {
  useEffect(() => {
    console.group("자식 컴포넌트");
    console.log("자식 컴포넌트도 리렌더링 되고 있어요.");
    console.groupEnd();
  });
  return <div></div>;
};

export default UpdateChild;
  • 자식요소도 부모요소에 영향을 받는다. 같이 리렌더링 되는 모습입니다.