TL;DR
useEffect
์์ ์์กด์ฑ ๋ฐฐ์ด์ ์ ํํ ์ค์ ํ์ง ์์ผ๋ฉดreact-hooks/exhaustive-deps
ESLint ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๋ค.- ์์กด์ฑ ๋ฐฐ์ด์๋ ์ฝ๋ ๋ด์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ณ์์ ํจ์๊ฐ ํฌํจ๋์ด์ผ ํ๋ค.
exhaustive-deps
๊ฒฝ๊ณ ์ ํด๊ฒฐ ๋ฐฉ๋ฒuseCallback
์ ์ฌ์ฉํ์ฌuseEffect
๊ฐ ์คํ๋ ๋ ํจ์๊ฐ ์ฌ์์ฑ๋์ง ์๋๋ก ์ต์ ํuseEffect
๋ด๋ถ๋ก ํจ์๋ฅผ ์ด๋์์ผ useEffect ๋ด์์๋ง ์ ์๋๋๋ก ํ์ฌ ์ธ๋ถ์ ๋ณ๋์ ์์กด์ฑ์ ์ถ๊ฐํ ํ์๊ฐ ์์ด์ง๋ค.
exhaustive-deps ๊ฒฝ๊ณ ์ ์์ธ
๋ฆฌ์กํธ์์ useEffect๋ฅผ ์ฌ์ฉํ ๋ react-hooks/exhaustive-deps
๋ผ๋ ESLint ๊ฒฝ๊ณ ๋ฅผ ๋ง์ฃผํ ๋๊ฐ ๋ง์๋ค. ์ด ๊ฒฝ๊ณ ๋ ์์กด์ฑ ๋ฐฐ์ด์ด ์ ํํ ์ค์ ๋์ง ์์์ ๋ ๋ฐ์ํ๋ ๊ฒฝ๊ณ ์๋ค. ์ด๋ฒ ๊ธ์์๋ ์์กด์ฑ ๋ฐฐ์ด๊ณผ exhaustive-deps ๊ฒฝ๊ณ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ด๋ป๊ฒ ์ค์ ํด์ผํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด ๊ท์น์ด ๋์
๋ ๋ฐฐ๊ฒฝ์ ๋ํด ๋ค๋ค๋ณด์๋ค.
๋ฆฌ์กํธ์ ์์กด์ฑ ๋ฐฐ์ด
๋ฆฌ์กํธ ํ ์ useEffect๋ฅผ ๋ฐํ์ผ๋ก ์ดํด๋ณด๋ฉด, ์์กด์ฑ ๋ฐฐ์ด์ useEffect์ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋๋ ๋ฐฐ์ด์ด๋ฉฐ ์ค์ ํจ์์ ์ฝ๋ ๋ด๋ถ์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ๋ค์ด ํฌํจ๋์ด์๋ค. ์ด ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค effect๊ฐ ์คํ๋๊ฒ ๋๋ค. ๋ฐ๋ผ์ ์์กด์ฑ ๋ฐฐ์ด์ useEffect๊ฐ ์ธ์ ์คํ๋ ์ง๋ฅผ ๊ฒฐ์ ํ๊ณ ๋ถํ์ํ ์ฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ค.
- ๋น ๋ฐฐ์ด์ ๋ฃ์ผ๋ฉด ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ง์ดํธ๋ ๋ effect๊ฐ ์คํ๋๋ฉฐ ๋ฐฐ์ด์ ์๋ตํ๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋ ๋๋ง๋ค effect๊ฐ ์คํ๋๋ค.
์ฃผ์ํ ์ ์ Effect์ ์์กด์ฑ์ โ์ ํโํ ์ ์๋ค๋ ์ ์ด๋ค. ์์กด์ฑ ๋ฐฐ์ด์๋ ์ฝ๋ ๋ด๋ถ์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ด ํฌํจ๋๋ค๊ณ ํ๋๋ฐ ์ฌ๊ธฐ์ ๋ฐ์ํ ๊ฐ์ด๋ props์ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ ์ธ๋ ๋ชจ๋ ๋ณ์, ํจ์๋ค์ด ํฌํจ๋๋ค.
useEffect ๋ด์์ ์ฌ์ฉํ๋ ์ธ๋ถ ๋ณ์๋ ํจ์๋ฅผ ์์กด์ฑ ๋ฐฐ์ด์ ๋ชจ๋ ์ถ๊ฐํด์ผํ๋๋ฐ ์ฝ๋๋ฅผ ์์ฑํ๋ค๋ณด๋ฉด ์์กด์ฑ์ ํฌํจํด์ ๋ถํ์ํ useEffect์ ์คํ์ ์ผ์ผํค๋ ๋ฐ์ํ ๊ฐ์ด ์๊ธธ ์ ์๋ค. ์ด ๋ฐ์ํ ๊ฐ์ ์ ๊ฑฐํ๋ค๋ฉด exhaustive-deps ๊ฒฝ๊ณ ๊ฐ ๋ํ๋๊ณ ์ด๋ฅผ ๋จ์ํ // eslint-disable-next-line react-hooks/exhaustive-deps
์ฃผ์์ ์ฌ์ฉํด์ ๊ท์น์ ๋นํ์ฑํํ ์๋ ์์ง๋ง ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ํ์ฌ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ผํ๋ค.
์์กด์ฑ ๋ฐฐ์ด ๊ฒฝ๊ณ ์ ๋ํ ํด๊ฒฐ์ฑ
๋จผ์ ๋ค์์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ์ฒ์์ ์ ๋์ํ์ง๋ง ๋ฌธ์ ์ ์ด ์๋ค.
import { useState, useEffect } from 'react';
function MyComponent({ searchKeyWord }) {
const [data, setData] = useState([]);
// ๋ฐ์ดํฐ fetching ํจ์
async function fetchData() {
const response = await fetch(`https://api.example.com/search?q=${searchKeyWord}`);
const result = await response.json();
setData(result);
}
useEffect(() => {
fetchData();
}, []);
return (
<div>
{data.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
useEffect์ ์์กด์ฑ ๋ฐฐ์ด์ด ๋น ๋ฐฐ์ด๋ก ์ค์ ๋์ด ์๋ค๋ ์ ์ด๋ค. searchKeyWord
๊ฐ ๋ณ๊ฒฝ๋์ด๋ useEffect๊ฐ ์ฌ์คํ๋์ง ์์ ๊ฒ์์ด๊ฐ ๋ฐ๋์์ ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ fetchingํ์ง ์๋๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด useEffect ์์ผ๋ก fetchData
ํจ์๋ฅผ ์ด๋ํ๊ณ ์์กด์ฑ ๋ณ์์ searchKeyWord
๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
useEffect(() => {
async function fetchData() {
const response = await fetch(`https://api.example.com/search?q=${searchKeyWord}`);
const result = await response.json();
setData(result);
}
fetchData();
}, [searchKeyWord]);
์์กด์ฑ์ ์ถ๊ฐํด์ฃผ๋ฉด์ searchKeyWord
๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค fetchData ์คํ๋์ด ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์
๋ฐ์ดํธ๋๋ค.
์ ์ด ๋ฐฉ์์ด ๋ ๋์๊น?
- ์ฐ์ ์์กด์ฑ ๊ด๋ฆฌ๊ฐ ์ฉ์ดํด์ง๋ค.
fetchData
๊ฐ useEffect ๋ด์์๋ง ์ ์๋๋ฉด ์ธ๋ถ์ ๋ณ๋์ ์์กด์ฑ์ ์ถ๊ฐํ ํ์ ์์ด useEffect์์ ์ฒ๋ฆฌ๋๋ฏ๋ก ๊ด๋ฆฌ๊ฐ ๊ฐํธํ๋ค. - ์ฝ๋์ ๊ฐ๋ ์ฑ์ด ํฅ์๋๋ค. ํจ์๊ฐ useEffect ์์ ๋ฌถ์ฌ ์์ด ์ฝ๋ ํ๋ฆ์ด ํ๋์ ๋ค์ด์ค๊ณ ํ ์ด ์คํ๋ ๋ ๋ฌด์์ด ์คํ๋๋์ง ์ฝ๊ฒ ์ดํดํ ์ ์๋ค.
searchKeyWord
๋ฅผ ํด๋ก์ ๋ก ์ฐธ์กฐํ๋ ์ํฉ์์ ์ด์ ๊ฐ์ด ๊ณ์ ์ฐธ์กฐ๋ ์ํ์ด ์์ง๋งuseEffect
์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐ๋์ด ์ด ๊ฐ๋ค์ ์ต์ ์ํ๋ก ์ฌ์ฉํ ์ ์๋ค.
๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ์ด์ผ ํ ๊น?
์ฌ๋ฌ ๊ฐ์ useEffect์์ ๋์ผํ ํจ์๋ฅผ ํธ์ถํด์ผํ ๋๋ props๋ก ์ ๋ฌ๋ ํจ์์ผ ๊ฒฝ์ฐ์๋ ํจ์๋ฅผ useEffect ์์ ๋ฃ๋ ๊ฒ์ด ๋นํจ์จ์ ์ผ ์ ์๋ค. useEffect๊ฐ ์คํ๋ ๋๋ง๋ค ํจ์๊ฐ ์ฌ์์ฑ๋์ด ๋ถํ์ํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๊ณผ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋์ ์์์ฒ๋ผ ํจ์๊ฐ ์ปดํฌ๋ํธ์ ์ํ๋ props์ ์์กดํ์ง ์๋๋ค๋ฉด getFetchUrl ํจ์๋ฅผ ์ปดํฌ๋ํธ์ ์ธ๋ถ๋ก ๋์ด ์ฌ์ฌ์ฉํ ์ ์๋ค.
// โ
Not affected by the data flow
function getFetchUrl(query) {
return 'https://hn.algolia.com/api/v1/search?query=' + query;
}
function SearchResults() {
useEffect(() => {
const url = getFetchUrl('react');
// ... Fetch data and do something ...
}, []); // โ
Deps are OK
useEffect(() => {
const url = getFetchUrl('redux');
// ... Fetch data and do something ...
}, []); // โ
Deps are OK
// ...
}
ํจ์๊ฐ ์ํ๋ props์ ์์กดํ์ง ์๊ธฐ ๋๋ฌธ์ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํ์ง ์์๋ ๋๋ค.
๋ค๋ฅธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก๋ useCallback ์ผ๋ก ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. getFetchUrl ํจ์๊ฐ ์์กด์ฑ ๋ฐฐ์ด์ ํฌํจ๋์ด๋ getFetchUrl ์ด ๋ณ๊ฒฝ๋์ง ์๋ ํ useEffect๊ฐ ๋ถํ์ํ๊ฒ ์ฌ์คํ๋์ง ์๊ฒ ๋๋ค.
์ด์ธ์๋ useEffectEvent
๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ๊ฐ์ฒด ์ ์ฒด๊ฐ ์๋ ํ์ํ ์์ฑ๋ง ์์กด์ฑ ๋ฐฐ์ด์ ํฌํจ์ํค๋ ๋ฐฉ๋ฒ ๋ฑ ์ํฉ์ ๋ง์ถฐ ๋ถํ์ํ ์์กด์ฑ์ ์ ๊ฑฐํ์ฌ ์ต์ ํํ ์ ์๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ์์ด ์์๋ค.
exhaustive-deps ๊ท์น์ด ๋์ ๋ ๋ฐฐ๊ฒฝ
๋ฆฌ์กํธ ํ ์ ์ฌ์ฉํ ๋ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ์ค ํ๋๋ stale closure ๋ฌธ์ ์ด๋ค. ํจ์ํ ์ปดํฌ๋ํธ์์ ์ํ๋ props๋ฅผ ์ฐธ์กฐํ๋ ํจ์๊ฐ ์ต์ ๊ฐ์ ๋ฐ์ํ์ง ์๊ณ ์ด์ ๊ฐ์ ๊ณ์ ์ฐธ์กฐํ๊ฒ ๋์ด ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ์ ์๋ค. ๋ฐ๋ผ์ ์์กด์ฑ ๋ฐฐ์ด์ ์ ํํ ์ค์ ํ๋๋ก ํด๋น ๊ท์น์ด ๋์ ์ด ๋์๋ค. ์ด ๊ท์น์ ๋ฐ๋ฅธ๋ค๋ฉด ํ ์ ์๋๋ ๋์์ ๋ณด์ฅํ๊ณ ์์ํ์ง ๋ชปํ ๋ฒ๊ทธ๋ฅผ ์ค์ผ ์ ์๋ค.
exhaustive-deps ๊ท์น์ ์งํค๋ ์ด์
- ์์กด์ฑ์ ์ ํํ ๋์ดํ๋ฉด ํด๋น ์์กด์ฑ์ด ๋ณ๊ฒฝ๋ ๋ ํ ์ด ๋ค์ ์คํ๋๋ฏ๋ก ์๊ธฐ์น ์์ ๋์์ ๋ฐฉ์งํ ์ ์๋ค.
- ์์กด์ฑ์ ์ ํํ๊ฒ ์ค์ ํจ์ผ๋ก์จ ๋ฆฌ์กํธ๊ฐ ์ฌ๋ ๋๋ง์ ์ต์ ํํ ์ ์๋ค. (useCallback)
- ์๋ชป๋ ์์กด์ฑ์ผ๋ก ์ธํ ๋ฒ๊ทธ๋ฅผ ์ค์ผ ์ ์๋ค.
์ฐธ๊ณ ์๋ฃ
- useEffect - React ๋ฌธ์
- A Complete Guide to useEffect - overreacted
- ์ exhaustive-deps๋ฅผ ์ง์ผ์ผํ๋์ง์ ๋ํด ๋ ผ์ํ๋ issue