useEffect의 의존성 배열에 값을 넣어주게 되면, 렌더링된 이후와 넣어준 값이 바뀔 때 해당 useEffect에 넘겨준 함수가 실행된다.
그렇다면 리액트는 넣어준 값이 언제 바뀌었다고 판단할까? 즉, 이전 상태와 이후 상태를 어떤 알고리즘을 통해 비교하는지 알아보자.
리액트는 Object.is()
알고리즘을 통해 새로운 값을 그 이전 값과 같은지 비교한다.
(공식 문서에서 찾을 수는 없었으나, 해당 링크에 설명되어있다.)
다음과 같이 사용하여, value1
과 value2
가 서로 같은 값인지 여부를 나타내는 Boolean 값을 반환한다.
Object.is(value1, value2);
다음 중 하나를 만족하면 두 값은 같다.
예시
// 특별한 경우
Object.is(0, -0); // false
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true
위 Object.is()
알고리즘에서 같은 객체이려면 객체에 대한 ‘참조 값’(객체가 저장되어 있는 메모리 주소)이 같아야 한다.
따라서 다음의 값은 false가 된다.
Object.is([], []); // false
그렇다면 여기서 의존성 배열에 넣어준 값이 객체이고,
객체 내부 속성의 이름과 값이 전부 같지만 참조 값이 다르다면
리액트는 다른 값으로 판단해야 한다.
한 번 테스트 해보자.
const [stateTest, setStateTest] = useState({
name: "dahyeon",
say: "hello",
});
useEffect(() => {
setStateTest({
name: "dahyeon",
say: "hello",
});
}, [viewportSize]);
useEffect(() => {
console.log(stateTest);
}, [stateTest]);
위 코드는 화면 사이즈(viewportSize)를 변경할 때마다 stateTest
라는 값을 바꾸도록 구현된 코드이다. 만약 stateTest
값이 바뀌었다면 (리액트에서 다르다고 판단하였다면) 그 값이 출력된다.
그 결과는 예상한 것처럼 다음과 같다.
즉, 값의 타입이 객체이고, 객체 내부 속성의 이름과 값이 전부 같더라도 참조 값이 다르다면 리액트는 다르다고 판단한다.
다르게 말하면,
참조 값이 같으면 같다고 판단한다.
위 테스트 코드를 살짝 바꿔서,
const [stateTest, setStateTest] = useState({
name: "dahyeon",
say: "hello",
});
useEffect(() => {
console.log("setStateTest 실행됨");
setStateTest(stateTest);
}, [viewportSize]);
useEffect(() => {
console.log(stateTest);
}, [stateTest]);
화면 사이즈(viewportSize)를 변경할 때마다 stateTest
라는 값을 현재의 stateTest
로 설정하도록 만들어보았다.
실행 결과 위와 같이 setStateTest가 실행되더라도 참조값은 같기 때문에, 리액트는 같다고 인식하는 것을 알 수 있다.
Object.is()
알고리즘을 통해 비교한다.참고자료
Understanding Referential Equality in React
Object.is() - JavaScript | MDN