useEffect

김석·2023년 9월 7일
0

React

목록 보기
4/14

1. useEffect란

  • 컴포넌트의 생명주기에 따른 side effect를 관리하는데 사용
  • 해당 컴포넌트가 DOM에 처음 출현했을 때(마운트 되었을 때), DOM에서 사라졌을 때(언마운트 되었을 때), 컴포넌트의 props가 변경되었을 때(마운트, 언마운트되지 않지만 감지해야하는 경우가 있을 수 있음), 컴포넌트 내부의 state가 변경되었을 때 특정 일을 수행하게끔 만드는 훅
  • 이 모든 기능을 useEffect 훅의 문법을 통해 해결함

2. useEffect 사용 예시

  1. 컴포넌트가 처음으로 화면에 표시될 때(마운트 시) 특정 작업을 수행하고 싶을 때 사용. 예를 들어 데이터를 API로 불러오거나, 이벤트 리스너를 추가할 때
  2. 컴포넌트가 화면에서 사라질 때 특정 작업을 수행하고 싶을 때 사용. 예를 들어 이벤트 리스너를 제거하거나, 타이머를 해제할 때
  3. 컴포넌트의 props가 변경될 때 사용.
    예를 들어,
function App() {
  const [currentId, setCurrentId] = useState(1);

  return (
    <div>
    <UserProfile userId={currentId} />
<button onClick={() => setCurrentId(2)}>ID2로 변경</button>
</div>
);
}

이런 경우 UserProfile에 집중해보자.
버튼 클릭 시 UserProfile이 1 -> 2로 바뀌지만, UserProfile는 언마운트 후 마운트 되지 않는다. 그냥 값만 바뀌고, 재렌더링만 된다. UserProfile 컴포넌트 안에서 useEffect를 사용하면 이를 감지 후 적절한 처리 및 새로 데이터 불러오기 등의 로직을 수행할 수 있음.
따라서 사용자의 입력에 따라 결과를 계산하거나, 변경된 데이터를 API에 저장할 때 사용됨
4. 컴포넌트의 상태가 변경될 때 사용.
state가 변경됨을 감지해서, 그에 맞는 로직을 수행할 때 사용.

3. useState 문법

useEffect(() => {
  // 컴포넌트가 마운트 되거나 업데이트될 때 실행됩니다.
  console.log("component updated");

  return () => {
    // 컴포넌트가 언마운트 되거나 이전의 useEffect가 다시 실행되기 전에 실행됩니다.
    console.log("cleanup");
  };
}, [someState]); // someState가 변경될 때만 useEffect 내의 코드가 실행됩니다.

예시

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

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

  useEffect(() => {
    console.log("useEffect 실행!");

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

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}
  1. 컴포넌트가 처음 렌더링 됨 -> useEffect 실행! 출력
  2. 의존성 배열에 있는 count 값이 바뀜 -> useEffect 함수 재실행됨
    : return의 cleanup 출력 후, 다시 useEffect 실행! 출력
  3. 컴포넌트 DOM에서 삭제됨 -> cleanup 출력

4. 코드 보고 구조 설명

import React, { useEffect } from 'react';

function User({ user, onRemove, onToggle }) {
  useEffect(() => {
    console.log('user 값이 설정됨');
    console.log(user);
    return () => {
      console.log('user 가 바뀌기 전..');
      console.log(user);
    };
  }, [user]);
  return (
    <div>
      <b
        style={{
          cursor: 'pointer',
          color: user.active ? 'green' : 'black'
        }}
        onClick={() => onToggle(user.id)}
      >
        {user.username}
      </b>
      &nbsp;
      <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}

function UserList({ users, onRemove, onToggle }) {
  return (
    <div>
      {users.map(user => (
        <User
          user={user}
          key={user.id}
          onRemove={onRemove}
          onToggle={onToggle}
        />
      ))}
    </div>
  );
}

export default UserList;
  1. UserList에서 User 컴포넌트를 3번 불렀다고 가정. 그러면 User 컴포넌트는 3번 마운트됨. 각 사용자 정보마다 총 3번 마운트
  2. 각각 User 컴포넌트에서 useEffect 호출됨
  3. User 컴포넌트가언마운트되면 useEffect의 cleanup 함수(return 부분)이 호출됨
  4. 의존성 배열 (deps)에 속해 있는 user이 달라지면, cleanup 함수가 호출되고, useEffect 함수가 다시 호출됨.
  5. 따라서 useEffect 내부에서 사용하는 상태나 props는 의존성 배열에 있어야, 방금 바뀐 최신의 값으로 로직을 수행할 수 있게 됨
  6. deps에 빈 배열이 아니라, 아무 것도 넣지 않는다면, 컴포넌트가 리렌더링 될 때마다 useEffect가 실행됨.

참고) 리액트 컴포넌트는 기본적으로 부모 컴포넌트가 리렌더링 되면 자식 컴포넌트 또한 리렌더링 됨.


5. 의존성 배열 관련

useEffect 내부에서 참조하는 값이 변경될 가능성이 있는 props거나 state인 경우, 의존성 배열에 넣어야 하는 이유?

넣지 않았을 때

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

useEffect(() => {
    const interval = setInterval(() => {
        console.log(count); // 항상 초기 값 0을 출력합니다.
    }, 1000);

    return () => clearInterval(interval); // cleanup
}, []);
  • 첫 실행 시, useEffect가 실행됨.
  • setInterval은 비동기 함수이기 때문에, useEffect는 종료되고, setInterval만 계속 수행됨
  • 매 초 0을 출력
  • count가 변하는 경우에도, 지금 count는 붙잡혀있는 상태
  • 계속 0이 출력됨
  • 의존성 배열에 변경될 가능성이 있는 변수를 넣지 않으면, useEffect가 참조하는 값은 해당 훅이 처음 실행되었을 때의 값으로 고정됨

넣었을 때

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

useEffect(() => {
    const interval = setInterval(() => {
        console.log(count); 
    }, 1000);

    return () => clearInterval(interval); // cleanup
}, [count]);
  • 첫 번째 코드와 마찬가지로 실행됨
  • count가 바뀐 경우, 먼저 현재 세션의 useEffect의 cleanup이 실행됨
  • 이후 다시 useEffect가 실행됨
  • 이 때 count는 최신의 값이 반영된 상태
  • 1이 출력됨

출처

https://react.vlpt.us/basic/16-useEffect.html

profile
handsome

0개의 댓글