๐ ์ด ๊ธ์ useEffect๋ฅผ ์ฌ์ฉํ๋ ์ค ๋ฌดํ ๋ฃจํ์ ๋น ์ ธ ๊ณจ๋จธ๋ฆฌ๋ฅผ ์ธ๋งค๋ฉฐ ๊ดด๋ก์ ํ๋ ์ฌ๋์ด ํ ๋ธ๋ก๊ทธ์ ๊ธ์ ๋ณด๊ณ ๊ฐ๋ช
๋ฐ์ ๋ฒ์ญํด ๊ฒ์ํ ๊ฒ์์ ์๋ ค๋๋ฆฝ๋๋ค.
๋ ์ค ๊ธฐ๋ฆฟ-
React์ useEffect Hook์ ์ฑ์ ๋ถ์์ฉ(side effects)์ ํด๊ฒฐํ ์ ์๊ฒ ํด์ค๋ค.
useEffect Hook์ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ช๋ช ๊ธฐ๋ฅ์ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
- ๋คํธ์ํฌ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ ์ค๊ธฐ
์ฒซ ๋ฒ์งธ ๋ง์ดํธ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ ์ฑ์ฐ๊ธฐ
- UI ์กฐ์
๋ฒํผ ํด๋ฆญ ์ ์ด๋ฒคํธ์ ์๋ตํ๊ธฐ (์: ๋ฉ๋ด ์ด๊ธฐ)
- ํ์ด๋จธ ์ค์ ๋๋ ์ข
๋ฃ
ํน์ ๋ณ์๊ฐ ๋ฏธ๋ฆฌ ์ ์๋ ๊ฐ์ ๋๋ฌํ๋ฉด ๋ด์ฅ๋ ํ์ด๋จธ๊ฐ ์ค์ง๋๊ฒ ํ๊ฑฐ๋ ์์๋๊ฒ ํ๊ธฐ
UseEffect Hook์ ์ฌ์ฉํ๋ ๊ฒ์ React ์ํ๊ณ์์ ์ผ๋ฐ์ ์ด์ง๋ง ๋ง์คํฐํ๋ ๋ฐ๋ ์๊ฐ์ด ํ์ํ๋ค. ์ด ๋๋ฌธ์ ๋ง์ ์ด๋ณด ๊ฐ๋ฐ์๋ ๋ฌดํ ๋ฃจํ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๋ ๋ฐฉ์์ผ๋ก useEffect ํจ์๋ฅผ ๊ตฌ์ฑํ๋ค. ์ ๋ช ๋์ ๋ฌดํ ๋ฃจํ์ ๊ทธ๊ฒ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ฐฐ์๋ณด์.
useEffect ํจ์์ ์ข ์์ฑ์ด ์์ผ๋ฉด ๋ฌดํ ๋ฃจํ๊ฐ ๋ฐ์ํ๋ค.
function App() {
const [count, setCount] = useState(0); //์ด๊ธฐ๊ฐ์ 0.
useEffect(() => {
setCount((count) => count + 1); //์ด Hook์ ์ฆ๊ฐ์ํจ๋ค.
}); //๋ํ๋์ ์ด๋ ์ด(์ข
์์ฑ ๋ฐฐ์ด) ์์.
return (
<div className="App">
<p> value of count: {count} </p>
</div>
);
}
์ข ์์ฑ์ด ์๋ ๊ฒฝ์ฐ ๋ชจ๋ ์ ๋ฐ์ดํธ ์ฃผ๊ธฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ฌ์ฉํ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฌ๊ธฐ์ ์ฑ์ ๋ชจ๋ ๋ ๋์ ๋ํด setCount ์ ๊ธฐ๋ฅ์ ์คํํ๋ค. ์ด๊ฒ์ด ๋ฌดํ ๋ฃจํ๋ฅผ ๋ฐ์์ํจ๋ค.
๋ฌธ์ ๋ฅผ ๋จ๊ณ๋ณ๋ก ๋๋์ด ๋ณด์.
์ด ๋ฌธ์ ๋ฅผ ์ํํ๋ ค๋ฉด ์ข ์์ฑ ๋ฐฐ์ด์ ์ฌ์ฉํด์ผ ํ๋ค. ํน์ ๊ฐ์ด ์ ๋ฐ์ดํธ๋๋ ๊ฒฝ์ฐ์๋ง React์์ useEffect๋ฅผ ํธ์ถํ๋๋ก ์ง์ํ๋ฉด ๋๋ค.
๋ค์ ๋จ๊ณ๋ก ๋ค์๊ณผ ๊ฐ์ ์ข ์์ฑ์ผ๋ก ๋น ๋ฐฐ์ด์ ์ถ๊ฐํ๋ฉด ๋๋ค.
useEffect(() => {
setCount((count) => count + 1);
}, []); //๋ ๋ฒ์งธ ์ธ์๋ก ๋น ๋ฐฐ์ด์ ์ค๋ค.
๋ ๋ฒ์งธ ์ธ์๋ก ๋น ๋ฐฐ์ด์ ์ฃผ๋ฉด, React๋ ์ฒซ ๋ฒ์งธ ๋ง์ดํธ์์๋ง setCount ํจ์๋ฅผ ์คํํ๋ค.
๋ฉ์๋๋ฅผ useEffect ์ข ์์ฑ ๋ฐฐ์ด์ ์ ๋ฌํ๋ฉด React๋ ๋ฌดํ ๋ฃจํ๊ฐ ์์์ ๋ํ๋ด๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค.
function App() {
const [count, setCount] = useState(0);
function logResult() {
return 2 + 2;
}
useEffect(() => {
setCount((count) => count + 1);
}, [logResult]); //๋ํ๋์๋ก logResult ํจ์๋ฅผ ์ค์ ํ๋ค.
return (
<div className="App">
<p> value of count: {count} </p> {/*count์ ๊ฐ ๋ณด์ฌ์ค*/}
</div>
);
}
์ด snippet์์๋ logResult ๋ฉ์๋๋ฅผ useEffect์ ์ข
์์ฑ ๋ฐฐ์ด์ ์ ๋ฌํ๋ค.
๋ฐ๋ผ์ ์ด๋ก ์ ์ผ๋ก๋, React๊ฐ ์ฒซ ๋ฒ์งธ ๋ ๋์์๋ง count ๊ฐ์ ์ฆ๊ฐ์ํฌ ๊ฒ์ด๋ผ๊ณ ์์๋๋ค.
ํ์ง๋ง! ์ด๋ฐ ์ค๋ฅ๊ฐ ๋จ๊ฒ ๋๋ค.
โ ๏ธ Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
๊ฒฝ๊ณ : ์ต๋ ์ ๋ฐ์ดํธ ๊น์ด๋ฅผ ์ด๊ณผํ์ต๋๋ค. ์ด ๋ฌธ์ ๋ ์ปดํฌ๋ํธ๊ฐ useEffect ์์ ์๋ setState๋ฅผ ํธ์ถํ์ง๋ง useEffect์ ์ข ์์ฑ ๋ฐฐ์ด์ด ์๊ฑฐ๋ ๋ชจ๋ ๋ ๋์์ ์ข ์์ฑ ์ค ํ๋๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์ ๋ฐ์ํ ์ ์์ต๋๋ค.
shallow comparison
)๋ผ๋ ๊ฐ๋
์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ด๋ค. ๋ํ๋์๊ฐ ์
๋ฐ์ดํธ๋์๋์ง ํ์ธํ๊ธฐ ์ํด ์ด ์์
์ ์ํํ๋ค.ํ ๊ฐ์ง ํด๊ฒฐ์ฑ
์ useCallback
Hook์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ์์ ์ ํจ์๋ฅผ ๋ฉ๋ชจํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํด ์ฐธ์กฐ ๊ฐ์ด ๋์ผํ๊ฒ ์ ์ง๋๋ค. React๋ ์์ ์ ์ธ ์ฐธ์กฐ ๊ฐ์ผ๋ก ์ธํด UI๋ฅผ ๋ฌดํํ ๋ค์ ๋ ๋๋งํ์ง ์์์ผ ํ๋ค.
const logResult = useCallback(() => {
return 2 + 2;
}, []); //์ด์ logResult๊ฐ ๋ฉ๋ชจ๋๋ค.
useEffect(()=> {
setCount((count)=> count+1);
},[logResult]); //logResult ์ฐธ์กฐ๊ฐ ๋์ผํ๊ฒ ์ ์ง๋๋ฏ๋ก ๋ฌดํ ๋ฃจํ ์ค๋ฅ๊ฐ ์์ด์ง๋ค.
๋ฐฐ์ด ๋ณ์๋ฅผ ์ข ์์ฑ์ผ๋ก ์ ๋ฌํ๋ฉด ๋ฌดํ ๋ฃจํ๊ฐ ์คํ๋๋ค.
const [count, setCount] = useState(0); //์ด๊ธฐ ๊ฐ์ 0.
const myArray = ["one", "two", "three"];
useEffect(() => {
setCount((count) => count + 1); //์ด์ ์ฒ๋ผ Count ๊ฐ์ ์ฆ๊ฐ์ํจ๋ค.
}, [myArray]); //๋ฐฐ์ด ๋ณ์๋ฅผ ๋ํ๋์๋ก ์ ๋ฌ
์ข ์์ฑ ์ธ์๋ก ๋ฐฐ์ด์ธ myArray ๋ณ์๋ฅผ ์ ๋ฌํ๋ค.
myArray์ ๊ฐ์ ๋ณํ์ง ์์๋๋ฐ ์ ์ฝ๋๊ฐ useEffect๋ฅผ ์ฌ๋ฌ ๋ฒ ํธ๋ฆฌ๊ฑฐํ ๊น?
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, ์ฐ๋ฆฌ๋ useRef
Hook์ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ ๊ฒํ๋ฉด ์ฐธ์กฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์๋๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
const [count, setCount] = useState(0);
//'current' ์์ฑ์ ์ถ์ถํ๊ณ ๊ฐ์ ํ ๋นํ๋ค.
const { current: myArray } = useRef(["one", "two", "three"]);
useEffect(() => {
setCount((count) => count + 1);
}, [myArray]); //์ฐธ์กฐ ๊ฐ์ด ์์ ์ ์ด์ด์ ๋ฌดํ ๋ฃจํ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
useEffec์ ์ข ์์ฑ ๋ฐฐ์ด์์ ๊ฐ์ฒด๋ฅผ ๋ฃ์ผ๋ฉด ๋ฌดํ ๋ฃจํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
const [count, setCount] = useState(0);
const person = { name: "Rue", age: 17 }; //๊ฐ์ฒด ์์ฑ
useEffect(() => {
//๋งค๋ฒ count ๊ฐ์ ์ฆ๊ฐ์ํด
//person'์ ๊ฐ์ ๋ณ๊ฒฝํจ
setCount((count) => count + 1);
}, [person]); //์ข
์ ๋ฐฐ์ด์ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ํฌํจํจ
return (
<div className="App">
<p> Value of {count} </p>
</div>
);
์ฝ์์ ๊ฒฐ๊ณผ๋ ํ๋ก๊ทธ๋จ์ด ๋ฌดํ ๋ฐ๋ณต๋จ์ ์๋ ค์ค๋ค.
The 'person' object makes the dependencies of useEffect Hook change on every render. Move it inside the useEffect callback. Alternatively, wrap the initialization of 'person' in its own useMemo() Hook.
'person' ๊ฐ์ฒด๋ ๋ชจ๋ ๋ ๋์์ useEffect Hook์ ๋ํ๋์๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค. 'person'๊ฐ์ฒด๋ฅผ useEffect ์ฝ๋ฐฑ ์์ผ๋ก ์ด๋ํ์ธ์. ๋๋ 'person'๊ฐ์ฒด์ ์ด๊ธฐํ๋ฅผ ์์ฒด useMemo() Hook์ผ๋ก ๋ํํ์ธ์.
useMemo
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ์ด Hook์ ๋ํ๋์๊ฐ ๋ณ๊ฒฝ๋ ๋ ๋ฉ๋ชจ๋ ๊ฐ์ ๊ณ์ฐํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฉ๋ชจ๋ ๋ณ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ๊ฐ ๋ ๋๋ง ์ค์ ์ํ์ ์ฐธ์กฐ ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์๋๋กํด์ค๋ค.
//useMemo๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด ์์ฑ
const person = useMemo(
() => ({ name: "Rue", age: 17 }),
[] //๋ํ๋์๊ฐ ์์ผ๋ฏ๋ก ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์๋๋ค. ์ฆ, useEffect์์ person๊ฐ์ฒด๋ฅผ ๋ํ๋์๋ก ์ฌ์ฉํด๋ ์ฐธ์กฐ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ ์ง๊ฐ ๋๋ค๋ ๋ป์ด๋ค.
);
useEffect(() => {
setCount((count) => count + 1);
}, [person]);
useEffect ํจ์์ ์๋ชป๋ ๋ณ์๋ฅผ ์ ๋ฌํ๋ฉด React๊ฐ ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค.
const [count, setCount] = useState(0);
useEffect(() => {
setCount((count) => count + 1);
}, [count]); //์ข
์์ฑ ๋ฐฐ์ด์ count ์ ๋ฌํจ
return (
<div className="App">
<button onClick={() => setCount((count) => count + 1)}>+</button>
<p> Value of count{count} </p>
</div>
);
๋ฌดํ ๋ฃจํ๋ฅผ ์ ๊ฑฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋น ์ข ์์ฑ ๋ฐฐ์ด์ ์ฌ์ฉํ๋ฉด ๋๋ค.
const [count, setCount] = useState(0);
//์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ง์ดํธ๋ ๋๋ง 'count' ๊ฐ์ ์
๋ฐ์ดํธํ๋ค.
useEffect(() => {
setCount((count) => count + 1);
}, []);
์ด๋ ๊ฒ ํ๋ฉด ์ฒซ ๋ฒ์งธ ๋ ๋์์๋ง useEffect๊ฐ ์คํ๋๋ค.
React Hooks๋ ์ฌ์ด ๊ฐ๋ ์ด์ง๋ง ํ๋ก์ ํธ์ ํตํฉ ํ ๋ ๊ธฐ์ตํด์ผ ํ ๋ง์ ๊ท์น์ด ์๋ค. ์ด๋ ๊ฒํด์ผ ์ฑ์ด ์์ ์ (stable)์ผ๋ก ์ ์ง๋๊ณ ์ต์ ํ(optimized)๋๋ฉฐ ํ๋ก๋์ ์ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
๋ํ ์ต๊ทผ ๋ฆด๋ฆฌ์ค๋ Create React App CLI๋ ๋ฐํ์ ์ค์ ๋ฌดํ ๋ฃจํ ์ค๋ฅ๋ฅผ ๊ฐ์งํ๊ณ ๋ณด๊ณ ํ๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํ๋ก๋์ ์๋ฒ๋ก ์ ํํ๊ธฐ ์ ์ ๋ฐ๊ฒฌํ๊ณ ์ํํ ์ ์๋ค.
๐ ์ฐธ๊ณ : How to solve the React useEffect Hookโs infinite loop patterns | Hussain Arif
ESLint์์ useEffect์ ์์กด์ฑ ๋ฐฐ์ด ๊ฒฝ๊ณ ๋๋ฌธ์ ํ๋ค์๋๋ฐ, ๋๋ถ์ useRef, useCallback์ ์ด์ฉํ์ฌ ์ ์ ๋ฆฌํ์ต๋๋ค. ๊ธฐ์กด์๋ useCallback๋ง์ผ๋ก ํด๊ฒฐํ๋ ค๊ณ ํ์ง๋ง ์ ํด๊ฒฐ์ด ์๋๊ณ ๋ฌดํ๋ฃจํ์ํ์ ๋น ์ก๋๋ฐ useRef๊ฐ ๋ต์ด์๊ตฐ์! ๊ฐ์ฌํฉ๋๋ค