React useEffect 의 dependency array

simple하지만 monster가 될때도 있는 useEffect

1. 언제 실행되는걸까

const App = () => {
useEffect(() => {
});
return <div id="root">Hi</div>
}
useEffect(callback, dependencyArray)
useEffect(() => console.log("매 rendering 마다 실행"));

2. 조건부로 실행시키기

const count = 1;
useEffect(() => {
console.log("count가 변경되면 실행됩니다.", count);
}, [count]);

State가 변경될 때 callback을 실행시키기

const [count, setCount] = useState(0);useEffect(() => {
console.log("버튼을 누르면 count 상태가 변경되어서 callback이 실행됩니다.")
}, [count]);
return (
<div>
<button onClick={() => setCount(prevCount => prevCount+1)}>버튼
</button>
</div>
)

Prop이 변경될 때 callback을 실행하시키기

const useForm = ({schema}) => {  useEffect(() => {
console.log("이렇게 구현을 하면 어떻게 될까?")
}, [schema]);
}

A. Prop이 primitive types 인 경우 (Boolean, Number String, Null, Undefined)

const useForm = ({count} : {count: number) => {
useEffect(() => {
console.log("count 값이 변할 때 callback이 불립니다.);
}, [count]);
}

B. Prop이 Object인 경우 (Object, Function, Array)

const useForm = ({schema} : {schema: Object}) => {   useEffect(() => {
console.log("schema가 변경될 때 실행시키고 싶지만, 현실은 매 rendering 마다 실행됩니다.")
}, [schema]);}const App = () => {
const [count, setCount] = useState(0);
const form = useForm({schema: {name: "required"}});return (
<div>
<button onClick={() => setCount(prevCount => prevCount+1)}>
버튼A
</button>
</div>
}

해결책 같아 보이는 후보들

useState (X)

const useForm = ({schema} : {schema: Object}) => {   useEffect(() => {
console.log("schema 값이 변하지 않아도 실행됩니다.")
}, [schema]);
}
const App = () => {
const [schema, setSchema] = useState(0);
const form = useForm({schema});return (
<div>
<button onClick={() => setSchema(schema)}>
버튼A
</button>
</div>
}

…Object.keys (X)

useEffect(() => {
console.log("schema에 key가 추가되면 실행되지 않습니다.")
}, [...Object.keys(schema)]);
}

for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
var a = {name: "Sg"}Object.is(a,a) // true
Object.is(a, {name: "Sg"}) // false
var b = a;Object.is(a,b) // true

Array.join (O, 하지만 약간 꼼수)

useEffect(() => {
console.log("약간 꼼수 같지만, 원하는 바를 이루다!");
}, [Object.keys(schema).join()]

Props 변경시 callback을 실행시키는 올바른 해결책

import isEqual from "lodash-es"const useForm = ({schema}) => {
cosnt prevSchema = useRef();
useEffect(() => {
console.log("여기는 매번 렌더링 마다 실행됩니다.")

if(schema && !isEqual(schema, prevSchema.current)) {
console.log("schema 값이 변경될 때 실행됩니다.")
prevSchema.current = schema;
}
});
}

use-deep-compare-effect

import useDeepCompareEffect from "use-deep-compare-effect"const useForm = ({schema}) => {
useDeepCompareEffect(() => {
console.log("깊은 비교로 object를 비교한다. schema 값이 변할 때 실행된다.");
}, [schema]);
}
function useDeepCompareMemoize(value) {  
const ref = React.useRef()
if (!deepEqual(value, ref.current)) {
ref.current = value
}
return ref.current
}

useEffect 너무 편리하지만, 정확히 알자

--

--

Entrepreneur

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store