Effect Hook

1abme·2023년 4월 24일
0

React

목록 보기
12/12

🪝 React Hook


React에서 Hook이란, 함수형 컴포넌트에서 사용되는, state와 관련된 기술들을 모아서 일컫는 말이며 Hook은 class를 작성하지 않고도 state와 다른 React의 기능들을 사용할 수 있게 해준다. 대표적으로 useState()useEffect() 가 있다.

Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수입니다. Hook은 class 안에서는 동작하지 않습니다. 대신 class 없이 React를 사용할 수 있게 해주는 것입니다.

⚠️ Hook을 쓸 때 주의할 점

  • 최상위 (at the Top Level)에서만 Hook을 호출한다.
    • 반복문, 조건문 혹은 중첩된 함수 내에서는 Hook을 호출 할 수 없다.
    • 조건부로 effect를 실행하기를 원한다면, 조건문을 Hook 내부에 넣어야 한다.
    • Early return이 실행되기 전에 항상 React 함수의 최상위에서 Hook 을 호출해야 한다.
    • 이를 따라야 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출되는 것이 보장된다.
  • React 함수 내에서 Hook 을 호출한다.
    • Hook 을 일반적인 Javascript함수에서 호출 하면 안된다.
    • Custom Hook에서의 Hook호출은 가능하다.

😶‍🌫️ componentDidXxx()


React Hook 이 나오기전 클래스 컴포넌트의 componentDidMount ()componentDidUpdate () 와 같은 Life Cycle Hook 함수를 사용해 Side Effect를 처리했다.

// Hook 등장 전의 Side Effect 처리

import React, { Component } from "react";

class UserListClass extends Component {
  state = {
    loading: true,
    users: [],
  };

  componentDidMount() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then((users) => this.setState({ users, loading: false }));
  }

  render() {
    const { loading, users } = this.state;
    if (loading) return <div>Loading...</div>;
    return (
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    );
  }
}

예시를 살펴보자면 외부 API 연동을 통해 사용자 목록을 조회하는 React 컴포넌트가 있다. 이 클래스 컴포넌트는 로딩 여부와 사용자 목록을 this.state 필드의 loadingusers 속성에 각각 저장하고 있다.

이 컴포넌트가 최초 렌더링될 때는 loading 의 초기 값이 true 라서 Loading... 이라는 메시지가 화면에 나타난다. 하지만 곧 componentDidMount() 함수가 호출되면 API가 호출되어 그 응답 결과가 users 속성에 할당되고 loadingfalse 로 업데이트 된다. 따라서 화면에 있던 Loading... 메시지는 사라지고, 대신 사용자 이름들이 나타나게 된다.

이런 클래스 기반 컴포넌트는 함수 기반 컴포넌트에 비해 복잡하고 따라서 오류가 발생하기 쉽고 유지 보수가 힘들기 때문에 많은 React 개발자들은 이렇게 간단한 Side Effect 구현 조차도 클래스 기반 컴포넌트로 작성해야 한다는 점에 대해서 불평했고 때문에 React Hook의 useEffect 가 나오게 되었다.

✨ useEffect()


useEffect() 함수는 React component가 렌더링 될 때마다 특정 작업(Sied effect)을 실행할 수 있도록 하는 리액트이며 이를 사용하면 함수형 컴포넌트에서도 클래스형 컴포넌트에서 사용했던 생명주기 메서드를 사용할 수 있게 되었다.

useEffect 함수 불러오기

import React, { useEffect } from "react";

useState와 마찬가지로 함수 불러오기를 통해 함수를 불러와야만 사용이 가능하다.

기본 형태


useEffect(function, deps)

function

실행하고자 하는 함수

deps ([dep1, de2, ...])

배열형태, fuction을 실행시킬 조건

  • deps 에 특정값을 넣게되면 컴포넌트가 mount 될 때, 지정한 값이 업데이트 될 때 useEffect를 실행한다.

첫번째 인자 (function)


useEffect의 첫번째 인자는 함수이다. 해당 함수내에서 side effect를 실행하면 되며 실행 조건이 있다.

실행 조건

  • 컴포넌트 생성 후 처음 화면에 렌더링
  • 컴포넌트에 새로운 props가 전달되며 렌더링
  • 컴포넌트에 상태 (state)가 바뀌며 렌더링

새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행된다고 볼 수 있다.

두번째 인자 (deps)


조건부 effect 발생을 실행시키기 위해 필요한 useEffect 의 두번째 인자는 배열이다. 이 배열은 조건을 담고 있는데 여기서 조건은 boolean형태의 표현식이 아니라 어떤 값의 변경이 일어날 때를 의미한다. 배열엔 어떤 값의 목록이 들어가며 종속성 배열 (dependency array) 이라고 부른다.

이 때문에 useEffect화면에 첫 렌더링될 때, 그리고 종속성 배열의 value 값이 바뀔 때 라는 실행조건을 가지게 된다. 따라서 모든 state가 아닌 특정 state에 관해서만 Side effect를 실행시킬 수 있다.

useEffect 사용법


useEffect 에 대해서 익혔으니 이제 이를 응용해 여러 경우에서의 사용법을 알아보자.

컴포넌트가 mount 되었을 때 (나타날 때)

useEffect(() => {
  console.log("렌더링 될 때마다 실행");
});

deps 부분을 생략시 해당 컴포넌트가 렌더링 될 때마다 useEffect 가 실행된다.

컴포넌트가 한번만 실행되었으면 할 때 (처음 생성시에만)

useEffect(() => {
  console.log("맨 처음 렌더링될 때 한번 만 실행");
},[]);

deps 부분에 빈배열을 넣을시 해당 컴포넌트가 처음 생성시에만 useEffect 가 실행된다.

컴포넌트가 update 되었을 때 (props, state 변경)

useEffect(() => {
  console.log(name);
  console.log("name이라는 값이 업데이트 될 때만 실행");
},[name]);

특정값이 업데이트 될 때만 실행하고 싶을 땐 deps위치의 배열안에 실행조건을 넣어주어야한다. 업데이트뿐만 아니라 마운터 될 때도 실행되므로 업데이트 될 때만 실행된다.

컴포넌트가 update 되었을 때만 실행되었으면 할 때

const mounted = useRef(false);
useEffect(() => {
  if (!mounted.current) {
    mounted.current = true;
  } else {
    console.log(name);
    console.log("업데이트 될 때만 실행");
  };
},[name]);

useRef 는 리렌더링 하지 않고 컴포넌트의 속성만 조회&수정한다. 이를 이용해 컴포넌트 안의 변수를 관리하면 리렌더링을 막을 수 있다.

컴포넌트가 upmount 되었을 때 (사라질 때) & update 되기 직전에

useEffect(() => {
  console.log("컴포넌트 나타남");
  console.log(name);
  return () => {
    console.log("cleanUP 함수");
  };
});

useEffect 는 함수를 반환할 수 있는데 이 함수를 cleanUP이라고 한다. 만약 unmount 될 때만 cleanUp 함수를 실행시키고 싶다면 deps에 빈배열을 넣으면 된다. 만약 특정 값이 업데이트되기 직전에 cleanUP 함수를 실행시키고 싶다면 deps에 해당 값을 넣어주면 된다.

// 예시
import React, { useEffect, useState } from "react";

function UseEffect() {
  const [name, setName] = useState("초기 닉네임");

  useEffect(() => {
    console.log("컴포넌트 나타남");
    console.log(name);
    return () => {
      console.log("cleanUp 함수");
    };
  });

  const onClick = () => {
    setName("닉네임 변경");
  };
  return (
    <div>
      {name} <button onClick={onClick}>변경</button>
    </div>
  );
}

export default UseEffect;
profile
제가 이해하고 있는게 맞나요...?

0개의 댓글