useEffect
,useCallback
,useMemo
등
의존성 배열을 파라미터로 받는React Hooks
은
의존성 배열의 모든 값들의종속성(참조 값)
을 비교해서
다르다면 첫번째 파라미터로 받은 함수를 동작시킨다고 한다.실제로 Object.is() - MDN 메서드를 사용한다고한다.
=== 보다 엄격한 Object.is
[JavaScript] Object Methods - Object.is()
원시 타입
은 불변성을 가지고 있기 때문에 상관없다.
객체 타입
은heap
영역에 실제 값이 저장되어있고
call stack
에 저장되어 있는 것은 실제 값의 참조 값이다.그렇기 때문에 객체의 속성 값를 바꿔도 참조 값은 바뀌지 않기 때문에
Hook
이 동작하지 않아야 한다.즉, 새로운 객체가 식별자에 할당되어야만
Hook
이 동작한다.
하지만 그렇지 않다.
의존성 배열에 객체를 넣으면모든 행위
에서Hook
이 동작한다고 한다.
왜 그런지 이유를 알고 싶었는데 모듈 동작 구조를 까보는데 실패했다..
[React] React Hooks 실제 선언 위치예를 들어 객체의 속성을 변경해도 Hook이 동작한다.
번외
로 이 코드는 한 가지 문제점이 존재한다.
클릭하세요
버튼을 클릭하면 count 값이 1 증가하는데
useEffect
의 의존성 배열에는 user 만 있음에도 실행된다.개발자 모드
index.js 의 <React.StrictMode>
에서는
초기 렌더링시에useEffect
가 두번 동작 한다.배포 환경에서는 한번만 동작하니 넘어가길 바란다.
아니면 태그를 없애서 확인하길 바란다.import React, { useState, useEffect } from "react"; export default function App() { const [count, setCount] = useState(0); const user = { name: "Narcoker", age: 100 }; const handleButton = () => { setCount((prevCount) => prevCount + 1); }; useEffect(() => { console.log("참조 값이 변경되면 실행합니다."); }, [user]); return ( <> <h1>{count}</h1> <button onClick={handleButton}>클릭하세요</button> </> ); }
React의 컴포넌트는 State나 Props가 변경되면 즉시 재렌더링된다.
App() 함수가 처음부터 다시 실행된다는 의미이다.즉, 변수의 값이 재생성 됨에 따라 참조값이 바뀌게 된다.
따라서 user 의 참조값이 바뀌기 때문에 useEffect가 실행이 되는 것이다.참고로 hook들도 다시 선언된다.
하지만 내부적으로 상태값을 가지고 있으며
내부 메커니즘을 통해서 이 상태값은 유지가 된다.
객체 자체가 아닌 변경될 객체의 속성의 식별자를 의존성 배열에 삽입한다.
useEffect(() => { console.log("참조 값이 변경되면 실행합니다."); }, [user.name]);
객체를 JSON 문자열 값으로 변환하여 사용한다.
useEffect(() => { console.log("참조 값이 변경되면 실행합니다."); }, [user.name]);
._isEqual(prev, next)
Kent C.Dodds
가 개발한 라이브러리이다.
의존성 배열의 값들의 변경을 확인할때깊은 비교
를 한다.사용 시
객체
와객체를 가지고 있는 배열
만 의존성 배열에 추가하라고한다.
함수를 포함하는 객체는 의존성 배열에 넣으면 안된다고 한다.
의존성 배열에 추가하면 안되는 형태
const objectHasFunction = { func: () => {} }; useDeepCompareEffect(() => { console.log("함수를 가진 객체는 사용하지 말것"); }, [objectHasFunction]);
잘 동작하는 예제
import React, { useState } from "react"; import useDeepCompareEffect from "use-deep-compare-effect"; export default function App() { const [count, setCount] = useState(0); const user = { name: "Narcoker", age: 100, parent: { child: {} } }; const handleButton = () => { setCount((prevCount) => prevCount + 1); }; useDeepCompareEffect(() => { console.log("참조 값이 변경되면 실행합니다."); }, [user]); return ( <> <h1>{count}</h1> <button onClick={handleButton}>클릭하세요</button> </> ); }