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
sgwanlee

sgwanlee

Entrepreneur

More from Medium

React Router V5 vs V6

Redux Toolkit

ReactNative: Basic App skeleton (For Beginner)

Managing States With Redux Toolkit