useEffect(
() => {
doSomething(a, b);
},
[a, b], // deps array
);
배열 내에 여러 개의 값이 있다면 그중의 단 하나만 다를지라도 리액트는 effect를 재실행합니다.
이것이 의미하는 바는 다음과 같습니다. [count]를 useEffect
의 두 번째 인수로 넣었다고 가정해 봅시다.
만약 count가 5이고 컴포넌트가 리렌더링된 이후에도 여전히 count는 변함없이 5라면 리액트는 이전 렌더링 시의 값 [5]를 그다음 렌더링 때의 [5]와 비교합니다. 배열 내의 모든 값이 같기 때문에(5 === 5) 리액트는 effect를 건너뛰게 됩니다.
count가 6으로 업데이트된 뒤에 렌더링하면 리액트는 이전에 렌더링된 값 [5]를 그다음 렌더링 시의 [6]와 비교합니다. 이때 5 !== 6 이기 때문에 리액트는 effect를 재실행합니다. 이를 활용하면 최적화가 가능합니다.
또한 특정 state가 특정한 condition 일 때만 effect를 재실행하고 싶다면 deps 배열의 state에 특정 조건을 넣는 것도 가능합니다.
그 이유는 리액트는 배열 내부의 값들이 이전 값과 비교하여 달라졌는지만 검사하기 때문입니다. [state === 5]
와 같이 특정 조건을 배열에 넣는다면, state === 5
자체가 하나의 boolean
값으로 인식됩니다. 따라서 state가 1, 2, 3 등일 때는 false 값을 가지고 있다가 state가 5가 된 후 렌더링 된 값은 true
가 되어 false !== true 이기 때문에 리액트는 effect를 재실행하는 것입니다.
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count === 5]); // count가 5일 때만 effect를 재실행합니다.
deps 배열
에 객체를 넣는 건 추천되지 않습니다. 이전 렌더링과 현재 렌더링에서의 객체 값을 비교하기 어렵기 때문입니다. 객체를 넣기 위해서는 다음 예제와 같이 Obj && Obj[attr]
를 deps 배열에 넣어주는 것이 좋습니다.
다음 예제에서 me
는 초깃값이 null
인 상태이며, 자료형은 객체입니다.
import React, { useEffect } from 'react';
import Router from 'next/router';
useEffect(() => {
if (me) {
alert('로그인이 되어 메인 페이지로 이동합니다.');
Router.push('/'); // id가 생기면 signup 페이지에서 메인 페이지로 이동
}
}, [me && me.id]); // JavaScript에서 객체는 undefined일 수 있으니,
// `me` 값이 확실히 존재하는 지 판단하기 위해 `&& me.id`를 붙여 guard를 해주어야 합니다.