7-3. Hooks - useEffect

송한솔·2023년 4월 27일
0

ReactStudy

목록 보기
33/54

useEffect 사용해보기

useEffcet는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hooks입니다.

클래스형 컴포넌트의 componentDidMount와 componentDidUpdate를 합친형태로 보아도 무방합니다.

useState에서 기존에 만들엇던 Info.js에 useEffect를 한번 적용해 보겠습니다.
Info.js

// Info.js
import { useEffect, useState } from 'react';

const Info = () => {

    const [name, setName] = useState('');
    const [nickname, setNickname] = useState('');

    useEffect(() => {
        console.log('렌더링이 완료되었습니다!');
        console.log(name,nickname);
    });

    const onChangeName = e => {
        setName(e.target.value);
    };
    const onChangeNickname = e => {
        setNickname(e.target.value);
    }

    return (
        <div>
            <div>
                이름 : <input value={name} onChange={onChangeName}/>
                <br/>
                닉네임 : <input value={nickname} onChange={onChangeNickname}/>
            </div>
            <div>
                <p>이름: <b>{name}</b></p>
                <p>닉네임: <b>{nickname}</b></p>
                
            </div>
        </div>
    );
};

export default Info;

상단에 이미지를 보면 우측 콘솔부분에 렌더링이 완료되었습니다!가 두 번씩 출력되는데요.

이는 컴포넌트가 마운트되며 초기 렌더링이 완료되고, 렌더링되며 useEffect가 호출되고
페이지가 새로고침(실행)될때 콘솔이 초기화되며 이전에 출력된 로그들이 삭제됩니다.
따라서,

실행 후에 useEffect가 다시 실행되는 것처럼 보여도 useEffcet는 한번만 실행됩니다.


마운트될 때만 실행하고 싶을 때

useEffect에서 설정한 함수를 컴포넌트가 화면에 맨 처음 렌더링될 때만 실행하고 업데이트 시 실행하지 않고 싶다면 함수의 두 번째 파라미터를 비어 있는 배열을 넣어 주면 됩니다.

기존의 useEffect 코드를 다음과 같이 변경해 보세요.

Info.js

// Info.js
import { useEffect, useState } from 'react';

const Info = () => {

    const [name, setName] = useState('');
    const [nickname, setNickname] = useState('');

    useEffect(() => {
        console.log('마운트시에만 useEffect출력!');
        console.log(name,nickname);
    }, []);

    const onChangeName = e => {
        setName(e.target.value);
    };
    const onChangeNickname = e => {
        setNickname(e.target.value);
    }

    return (
        <div>
            <div>
                이름 : <input value={name} onChange={onChangeName}/>
                <br/>
                닉네임 : <input value={nickname} onChange={onChangeNickname}/>
            </div>
            <div>
                <p>이름: <b>{name}</b></p>
                <p>닉네임: <b>{nickname}</b></p>
            </div>
        </div>
    );
};

export default Info;

첫 마운트시 name,nickname은 공백이기 때문에 보이지 않지만
이후에 name,nickname의 값이 바뀌어도 useEffect가 실행되지 않는 것을 볼 수 있습니다.


특정 값이 업데이트될 때만 실행하고 싶을 때

useEffect를 사용할 때, 특정 값이 변경될 때만 호출하고 싶다면?

클래스형 컴포넌트에서는 다음과 같이 작성할 것입니다.

componentDidUpdate(prevProps, prevState){
	if(prevProps.value !== this.props.value}{
		doSomeThing(); 
	}
} 

이 코드는 특정 props의 value가 바뀌었을 때만 doSomething()을 수행합니다.

같은 작업을 useEffect에서 수행한다면 어떻게 해야할까요?

useEffect의 두 번째 파라미터 배열 안에 검사하고 싶은 값을 넣어주면 됩니다.

useEffect(() => {
  console.log('마운트시에만 useEffect출력!');
  console.log(name,nickname);
}, [name]);

name값만 체크하기에 닉네임의 state를 바꿀때에는 useEffect가 실행되지 않습니다.


여러개의 데이터를 체크해서 useEffect를 하고싶다면?

useEffect(() => {
        console.log('마운트시에만 useEffect출력!');
        console.log(name,nickname);
    }, [name,nickname]);

간단하게 두 번째 파라미터에 배열을 추가하여 추가한 배열의 데이터가 수정될 때 마다 useEffect를 실행할 수 있습니다.


뒷정리하기

useEffect는 기본적으로 렌더링 후에(렌더링될때마다) 실행되며,
두 번째 파라미터 배열에 무엇을 넣는지에 따라 실행조건이 달라집니다.

컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면
useEffect에서 뒷정리(cleanup)함수를 반환해 주어야 합니다.

Info 컴포넌트의 useEffect부분을 다음과 같이 수정해 보세요.

Info.js

// Info.js
import { useEffect, useState } from 'react';

const Info = () => {

    const [name, setName] = useState('');
    const [nickname, setNickname] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log(name,nickname);
        return () => {
            console.log('cleanup');
            console.log(name);
        }
    }, [name,nickname]);

    const onChangeName = e => {
        setName(e.target.value);
    };
    const onChangeNickname = e => {
        setNickname(e.target.value);
    }

    return (
        <div>
            <div>
                이름 : <input value={name} onChange={onChangeName}/>
                <br/>
                닉네임 : <input value={nickname} onChange={onChangeNickname}/>
            </div>
            <div>
                <p>이름: <b>{name}</b></p>
                <p>닉네임: <b>{nickname}</b></p>
            </div>
        </div>
    );
};

export default Info;

App.js

import { useState } from "react";
import Counter from "./Counter";
import Info from "./Info";

function App() {
  const [visible, setvisible] = useState(false);
  return (
    <div>
      <button onClick={()=>setvisible(!visible)}>
        {visible ? '숨기기' : '보이기'}
      </button>
      {visible && <Counter/>}
      <p>---------------------------------------</p>
      {visible && <Info/>}
    </div>
  );
}

export default App;

보이기 버튼을 눌렀을 때 두 번 마운트되면서 effect, cleanup, effect가 출력됩니다.
그 다음에 숨기기 버튼을 다시 누르면 cleanup이 호출됩니다.

한번 코드에 이름을 입력해봅시다.

뒷정리 함수(cleanup)는 업데이트되기 직전의 값만 나오는 것을 볼 수 있습니다.

마운트될 때만 실행하고 싶을 때와 같이 언마운트 시에만 뒷정리 함수를 호출하고 싶다면 두 번째 파라미터에 비어있는 배열을 넣으면 됩니다.

// 언마운트 시에만 실행하고 싶다면 두번째 파라미터를 공백으로.
useEffect(() => {
    console.log('effect');
    return () => {
        console.log('unmount');
    }
}, []);

어떤 경우에 사용하기 좋을까?

useEffect(() => {
  // 이벤트 리스너를 등록합니다.
  window.addEventListener("resize", handleResize);

  // 컴포넌트가 언마운트될 때 이벤트 리스너를 제거합니다.
  return () => {
    window.removeEventListener("resize", handleResize);
  };
}, []);

0개의 댓글