7-1강. Hooks - useEffect ( )

정원·2023년 1월 31일
0

React

목록 보기
19/42

2023.01.31 useEffect( )

useEffect

React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말한다.
React는 우리가 넘긴 함수('effect')를 기억했다가 DOM update를 수행한 이후에 불러낸다.

useEffect( )는 사이드 이펙트를 수행하기 위한 훅이다.


사이드 이펙트란??

사이드 이펙트는 사전적으로 부작용이라는 뜻을 갖고 있다.
개발자가 의도치 않은 코드가 실행되면서 버그가 나타나면 사이드 이펙트가 발생했다고 말한다.
하지만 리액트에서의 사이드 이펙트는 부정적인 의미는 아니다.

리액트에서 말하는 사이드 이펙트는 그냥 효과 혹은 영향을 뜻하는 이펙트의 의미에 가깝다.
예를 들면 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업을 의미한다.

React 컴포넌트가 화면에 렌더링된 이후에
비동기로 처리되어야 하는 부수적인 효과들을 Side Effect라고 한다.
대표적인 예로
어떤 데이터를 가져오기 위해서 외부 API를 호출하는 경우,일단 화면에 렌더링할 수 있는 것들을 먼저 렌더링하고
실제 데이터는 비동기로 가져오는 것이 권장된다.
요청 즉시 1차 렌더링을 함으로써 연동하는 API가 응답이 늦어지거나 응답이 없을 경우에도 영향을 최소화 시킬 수 있어서 사용자 경험 측면에서 유리하기 빼문이다.


useEffect( )는 리액트의 함수 컴포넌트에서
사이드 이펙트를 실행할 수 있도록 해주는 훅이다.

useEffect( )는 클래스 컴포넌트에서 제공하는 생명주기 함수인
componentDidMount( ),componentDidUpdate( ),componentWillUnMount( )와 동일한 기능을 하나로 통합해서 제공한다.
그래서 useEffect( ) 훅만으로 위의 생명주기 함수와 동일한 기능을 수행할 수 있다.


useEffect( ) 사용법

useEffect( )는 아래와 같이 사용한다.

useEffect(이펙트 함수, 의존성 배열);

첫 번째 파라미터로는 이펙트 함수가 들어가고
두 번째 파라미터로는 의존성 배열이 들어간다.

* 의존성 배열은 말 그대로 이 이펙트가 의존하고 있는 배열인데
배열 안에 있는 변수 중에 하나라도 값이 변경되었을 때 이펙트 함수가 실행된다.

기본적으로 이펙트 함수는 처음 컴포넌트가 렌더링된 이후와 업데이트로 인한
재렌더링 이후에 실행된다.
만약 이펙트 함수가 마운트와 언마운트시에 단 한 번씩만 실행되게 하고 싶으면,
의존성 배열에 빈 배열([ ])을 넣으면 된다.

useEffect(이펙트 함수, [ ]);

이렇게 하면 해당 이펙트가 props나 state에 있는 어떤 값에도 의존하지 않는 것이 되므로 여러번 실행되지 않는다.

의존성 배열은 생략할 수도 있는데 생략하게 되면 컴포넌트가 업데이트될 때마다 호출된다.

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

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

    //componentDidMount, componentDidUpdate와 비슷하게 작동한다.
    useEffect(()=> {
        //브라우저 API를 사용해서 document의 title을 업데이트 한다.
        document.title = `${conunt}번 클릭했습니다.`;
    });
    
    return (
        <div>
            <p>{count} 번 클릭 했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    );
}

위의 예제 코드는 앞에서 useState( )를 배울 때 살펴 본 코드와 거의 동일하며
추가로 useEffect( ) 훅을 사용하고 있다.

위 코드처럼 의존성 배열 없이 useEffect( )를 사용하면
리액트는 DOM이 변경된 이후에 해당 이펙트 함수를 실행하라는 의미로 받아들인다.
그래서 기본적으로 컴포넌트가 처음 렌더링 될 때를 포함해서 매번 렌더링될 때마다
이펙트가 실행된다고 보면 된다.
위 코드의 경우 이펙트 함수는 처음 컴포넌트가 마운트되었을 때
실행되고 이후 컴포넌트가 업데이트될 때마다 실행된다.

결과적으로 componentDidMount( ),componentDidUpdate( )와 동일한 역할을 하게 되는 것이다.
또한 이펙트는 함수 컴포넌트 안에서 선언되기 때문에 해당 컴포넌트의
props와 state에 접근할 수도 있다.


그렇다면 componentWillUnmount( )와 동일한 기능은 useEffect( )로 어떻게 구현할 수 있을까?

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

function UserStatus(props) {
    const [isOnline, setInsOnline] = useState(null);

    function handleStatusChange(status) {
        setInsOnline(status.isOnline);
    }

    useEffect(() => {
        ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
        return () => {
            ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
        };
    });

    if (isOnline === null) {
        return '대기중 ...';
    }
    return isOnline ? '온라인' : '오프라인';
}

위 코드는 useEffect( )에서 먼저 ServerAPI를 사용하여 사용자의 상태를 구독하고 있다.
이후 함수를 하나 리턴하는데 해당 함수 안에는 구독을 해지하는 API를 호출하도록 되어있다.
useEffect( )의 리턴 함수는 컴포넌트가 마운트 해제될 때 호출된다.
결과적으로 useEffect( )의 리턴 함수의 역할은 componentWillUnmount( ) 함수가 하는 역할과 동일하다.

또한 useEffect( ) 훅은 하나의 컴포넌트에 어러 개를 사용할 수도 있다.

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

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

    useEffect(()=> {
        document.title = `${conunt}번 클릭했습니다.`;
    });

    const [isOnline, setInsOnline] = useState(null);

    
    useEffect(() => {
        ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
        return () => {
            ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
        };
    });

    if (isOnline === null) {
        return '대기중 ...';
    }

    return (
        <div>
            <p>{count} 번 클릭 했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    );
}

useEffect( )훅 사용법 정리

useEffect(() => {
	//컴포넌트가 마운트 된 이후,
    //의존성 배열에 있는 변수들 중 하나라도 값이 변경되었을 때 실행됨
    //의존성 배열에 빈 배열( [ ] )을 넣으면 마운트와 언마운트시에 단 한 번씩만 실행됨
    //의존성 배열 생략 시 컴포넌트 업데이트 시마다 실행됨
    ...
    
    return () => {
    //컴포넌트가 마운트 해제되기 전에 실행됨
    ...
    }
}, [의존성 변수1, 의존성 변수2, ...]);

0개의 댓글