๐ก 06. useEffect ํ๊ดดํ๊ธฐ (2): ์์กด์ฑ ๋ฐฐ์ด์ ๊ฑฐ์ง๋ง
๐ ๊ฐ์
lint ๊ฒฝ๊ณ ๋ฅผ ๋ฌด์ํ๊ณ ์์กด์ฑ ๋ฐฐ์ด์ ์์ผ ๋ ๋ฐ์ํ๋ ๋ฌดํ ๋ฃจํ ์ฌํ์, ์ฌ๋ฐ๋ฅธ ํจ์/๊ฐ์ฒด ์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ์ ๋ํด ๋ถ์ํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- IDE(์๋ํฐ)๊ฐ ๋์์ฃผ๋
react-hooks/exhaustive-deps๊ฒฝ๊ณ ๋ฅผ ์ ์ ๋ ๋ฌด์ํ๋ฉด ์ ๋๋์ง ๊นจ๋ซ๋๋ค.- ํจ์๋ ๊ฐ์ฒด๋ฅผ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ์์ ๋ ๋ถํ์ํ๊ฒ ํ์ด๋จธ๊ฐ ๊ณ์ ์ฌ์์๋๋ ์์ธ(
๋ฉ๋ชจ๋ฆฌ ์ฐธ์กฐ๊ฐ ๋ฆฌ์ )์ ์์ ํ ์ดํดํ๋ค.- ํจ๊ณผ ๋ด๋ถ์์ ํ์ํ ํจ์๋ฅผ ์ด๋ป๊ฒ ๋ฐฐ์นํด์ผ ๋ฌดํ ๋ ๋ ํธ๋ฆฌ๊ฑฐ๋ฅผ ํผํ ์ ์๋์ง ์ฐ์ํ ์ค๊ณ๋ฒ์ ์ฒด๋ํ๋ค.
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ: ๋ฆฌ์กํธ์ ๊ฑฐ์ง๋ง์ ํ ๋๊ฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ํจ์์ ๊ฐ์ฒด, ์ฌ๋ฐ๋ฅด๊ฒ ์ฅ์ด์ฃผ๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 15๋ถ / ํต์ฌ ํํธ: 10๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์ฒ (์ ์
): "์์กด์ฑ ๋ฐฐ์ด์ ๋ญ ๋ฃ์ผ๋ผ๊ณ ๋
ธ๋์ lint ๊ฒฝ๊ณ ์ค์ด ์์ฒญ ๋จ๋๋ฐ, ๋ฃ์ผ๋๊น ํ์ด์ง๊ฐ ๋ฌดํ ์๋ก๊ณ ์นจ ๋๋ฉด์ ๋ป์ด๋ฒ๋ฆฌ๋๋ฐ์? ๊ทธ๋์ ๊ทธ๋ฅ ๊ฒฝ๊ณ ๋ฌด์ํ๋ ์ฃผ์(
// eslint-disable-next-line) ๋ฌ์์ต๋๋ค!" - ์ํธ(๋ฆฌ๋): "์์ฒ ๋... ๋ฆฌ์กํธ์๊ฒ ๊ฑฐ์ง๋ง์ ํ๋ฉด ๊ทธ ๋๊ฐ๋ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ๋ก ๋์์ต๋๋ค. ์ง๊ธ ๋น์ฅ ๊ทธ ์ฃผ์๋ถํฐ ์ง์ฐ์์ฃ ."
๐ค ์ ์์์ผ ํ๋๊ฐ: ๋ฆฌ์กํธ์ ๊ฑฐ์ง๋ง์ ํ ๋๊ฐ
useEffect๋ฅผ ์ฌ์ฉํ๋ค ๋ณด๋ฉด ๊ฑฐ์ ๋ชจ๋ ์ฃผ๋์ด ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ค์ด ์์กด์ฑ ๋ฐฐ์ด(Dependency Array, [])์ ์ฅ๋ฒฝ์ ๋ถ๋ชํ๋๋ค.
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
ํน์ ์ต์ (options)์ด ๋ฐ๋๋ฉด API ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ค๊ณ ํด.
์ ์๋ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ฌดํ ๋ฃจํ(์์ฒญ ํญ๊ฒฉ๊ธฐ)์ ๋น ์ ธ์ ๋ฐฑ์๋(์์) ์๋ฒ๊ฐ ํฐ์ ธ๋ฒ๋ฆด๊น?
// โ ์์ฒ ์ด์ ๋ฐฑ์๋ ํ
๋ฌ ์ฝ๋ (DDOS ์์ค)
function ProductList() {
const [data, setData] = useState(null);
// ์์ฒ : "์! ์กฐ๊ฑด ์ต์
๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด๋ฌ์ผ์ง."
const options = { limit: 10, sort: 'desc' };
// ์์ฒ : "API๋ฅผ ํธ์ถํ๋ effect๋๊น, options ์ต์
์ด ๋ฐ๋ ๋๋ง๋ค ์คํ๋์ด์ผ์ง!"
useEffect(() => {
fetchData('/api/products', options).then((res) => setData(res));
}, [options]); // ๐จ ์๋ฌ ํญํ ํธ๋ฆฌ๊ฑฐ! ๋ฌดํ ๋ฃจํ!
return <div>{JSON.stringify(data)}</div>;
}VS Code๋ ์์กด์ฑ์ ๋ํด ์ด๋ ํ ์๋ฌ๋ ๋์ฐ์ง ์์ต๋๋ค. ํ์ง๋ง ์ด ์ปดํฌ๋ํธ๋ ๋ฌดํํ ๋ฆฌ๋ ๋๋ง๋๋ฉฐ ์ด๋น 10๋ฒ์ฉ ์๋ฒ์ API ์์ฒญ์ ๋๋ฆฝ๋๋ค.
์์ฒ ์ด๋ ๋นํฉํด์ ์์กด์ฑ ๋ฐฐ์ด์ ์๋์ผ๋ก [] ๋น ๊ป๋ฐ๊ธฐ๋ก ๋ฐ๊พธ๊ณ (๊ฑฐ์ง๋ง), ๋
ธ๋ ๊ฒฝ๊ณ ์ค์ ๋ฌด์ํ๋ ์ฃผ์์ ๋ฌ์๋ฒ๋ฆฝ๋๋ค. ๊ณผ์ฐ ์ด ์ฝ๋๋ ๋ฌด์์ด ๋ฌธ์ ์์๊น์?
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์๋ง(๋ฆฌ์กํธ)๊ฐ ์์ฒ ์ด์๊ฒ ์์๋ฆฌ๋ฅผ ํฉ๋๋ค. "๋ค๊ฐ ์์ ์ฅ๊ณ ์๋ ๊ณผ์ ๋ด์ง(์์กด์ฑoptions)๊ฐ ๋ฐ๋๋ฉด ๋ด๊ฐ ์ ๊ธฐ ๊ฐ์ ์ฐฝ๋ฌธ ์ด์ด์ค๊ฒ(useEffect ์คํ)."
- ๋ฐฉ์ ์๋ก ๊พธ๋ฐ ๋๋ง๋ค(๋ฆฌ๋ ๋๋ง) ๋ฆฌ์กํธ๋
options = { limit: 10 }์ด๋ผ๋ ์ ๊ณผ์ ๋ด์ง๋ฅผ ํ๋ ๋ฏ์ต๋๋ค.- ์๋ง๊ฐ ๋ฌป์ต๋๋ค. "์ ๋ฒ ๋ ๋๋ง ์ค๋ ์ท ๋ ์ฅ ๊ณผ์๋ด์ง(
๊ณผ๊ฑฐ options)๋, ๋ฐฉ๊ธ ์๋ก ์ ์ธ๋ ๊ณผ์๋ด์ง(ํ์ฌ options)๋ ๋๊ฐ์?"- ์์ฒ ์ด๊ฐ ๋๋ตํฉ๋๋ค. "๋ด์ฉ๋ฌผ(10)์ ๊ฐ์๋ฐ์, ํฌ์ฅ์ง ๊ป๋ฐ๊ธฐ(๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ)๊ฐ ์์ ์ ๊ฑฐ์์! ๋ฌด์กฐ๊ฑด ์๋ก ๋ฏ์๊ฑฐ๋ ์!" (๊ฐ์ฒด ์์ ๋๋ฑ์ฑ ์คํจ)
- ์๋ง: "์ด? ๊ณผ์๊ฐ ๋ฐ๋์๋ค! ์ฐฝ๋ฌธ ๋ค์ ์ฐ๋ค!! (
useEffect ์คํ->setData ํธ์ถ-> ๋ฆฌ๋ ๋๋ง ๋ฐ์ -> 1๋ฒ์ผ๋ก ๋์๊ฐ ๋ฌดํ ๋ฐ๋ณต)"
โ
ํต์ฌ ์๋ฆฌ:
03. ๋ถ๋ณ์ฑ ๋ฌธ์์์ ๋ฐฐ์ ์ง? ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ์ฒด๋ ๋ฐฐ์ด, ํจ์๋ฅผ ๋งค๋ฒ ํธ์ถ(์ ๋ฆฌ๋ ๋๋ง)ํ ๋๋ง๋ค ๋ด์ฉ์ด ์๋ฒฝํ ๋๊ฐ์๋ ํ(Heap) ๋ฉ๋ชจ๋ฆฌ์ ์๋ก์ด ์ฃผ์๋ก ํ ๋นํด๋ฒ๋ฆฝ๋๋ค.
์ด ๊ฐ์ฒด/ํจ์ ์ฐธ์กฐ(Reference)๊ฐ useEffect์ ์์กด์ฑ ๊ฐ์๊ธฐ(๊ฐ์๋ด)์ ๋ค์ด๊ฐ๋ฉด, ๊ฐ์๋ด์ "์! ์ฃผ์๊ฐ ๋ฌ๋ผ์ก๋ค! ๋ฐ์ดํฐ๊ฐ ๋ฐ๋์๋ค!" ๋ผ๊ณ ์ฐฉ๊ฐํ๊ณ ๋ฌด์กฐ๊ฑด Effect ํ
์ ์ฌ์คํํด ๋ฒ๋ฆฝ๋๋ค. Effect ์์์ setData๊น์ง ์ณค์ผ๋, ์ด๋ ๋์๋ ์ฌ๋ ๋๋ง๊ณผ Effect ์ฌํธ์ถ์ ๋ฌด๊ฐ์ง์ฅ(๋ฌดํ ๋ฃจํ)์ด ๋๋ ๊ฒ๋๋ค.
๐งฉ ํจ์์ ๊ฐ์ฒด, ์ฌ๋ฐ๋ฅด๊ฒ ์ฅ์ด์ฃผ๊ธฐ
โ ์์ฒ ์ด์ ํํผ ๊ธฐ๋
์์ฒ ์ด๋ ์ด ๋ฌดํ ๋ฃจํ๋ฅผ ๊ฒช์, ๋ฌด์์์ ๊ฐ์ ๋ก ์์กด์ฑ ๋ฐฐ์ด์์ options๋ฅผ ์ง์๋ฒ๋ฆฝ๋๋ค.
useEffect(() => {
fetchData('/api/products', options).then((res) => setData(res));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // ๐จ ๋ฆฌ์กํธ์ ๊ฑฐ์ง๋ง์ ํ์.์ด๋ ๊ฒ ํ๋ฉด ๋ฃจํ๋ ๋ฉ์ถฅ๋๋ค! ํ์ง๋ง ์ง์ง ์น๋ช
์ ์ธ ๋ฒ๊ทธ๊ฐ ์ ๋ณตํ๊ฒ ๋ฉ๋๋ค. ๋ง์ฝ ์ ์ ๊ฐ ์ต์
์ '10๊ฐ ๋ณด๊ธฐ'์์ '50๊ฐ ๋ณด๊ธฐ'๋ก ๋ฒํผ์ ๋๋ฌ ๋ณ๊ฒฝํ๋ฉด, options ๋ณ์๋ ๋ฐ๋์ง๋ง useEffect๋ ์์ ์ด ์์กดํ๋ ๊ฐ์ด ์ ๋ฐ๋์๋ค([]์ด๋ฏ๋ก ๋ณํ ์ผ ์์)๊ณ ์๊ฐํด์ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋๊ธฐํ(Fetch)ํด ์ค์ง ์๋ ์ผ์ด๋ถ์ UI ์ํ ๊ฐ ๋ฉ๋๋ค. ๋ฆฌ์กํธ์๊ฒ ๊ฑฐ์ง๋ง์ ํ ๋๊ฐ์ฃ .
โ ์ํธ์ ๋ฆฌํฉํ ๋ง: ์ปดํฌ๋ํธ ๋ฐ์ผ๋ก ์น์ฐ๊ฑฐ๋ ํ์ดํค์ณ๋ผ
๋ฐฉ๋ฒ 1. ์ด์ฐจํผ ๊ณ ์ ์ธ ๋ฐ์ดํฐ๋ฉด ์ปดํฌ๋ํธ ์ค์ฝํ ๋ฐ์ผ๋ก ํ์ฅ์์ผ๋ผ!
์์กด์ฑ์ ๊ฑธ๋ฆฌ์ ๊ฑฐ๋ฆฌ๋ ๊ฐ์ฒด๊ฐ ์ํ(State)์ ์ ํ ๋ฌด๊ดํ ์ ์ (Static) ํ๊ฒฝ ์ค์ ์ด๋ผ๋ฉด, ์ปดํฌ๋ํธ ํจ์ ๋ฐ(๋ชจ๋ ์ค์ฝํ)์ผ๋ก ์ฌ๋ฆฌ๋ฉด ๋๋ฉ๋๋ค. ์ด ๊ฐ์ฒด๋ ํ์ ๋ฑ ํ ๋ฒ๋ง ๋ง๋ค์ด์ง๋ฏ๋ก ์ฐธ์กฐ ์ฃผ์๊ฐ ๋ฐ๋ ์ผ์ด ์์ฃ .
// โ
์ฐ์ํ ํ์ถ (Pro Approach 1)
const options = { limit: 10, sort: 'desc' }; // ๋ฐ์ผ๋ก ๋นผ๋ฒ๋ฆฌ๊ธฐ!
function ProductList() {
const [data, setData] = useState(null);
useEffect(() => {
// ์ด์ options๋ ์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์๋์์์ ์๋ฒฝํ ๋ฉด์ ๋ฉ๋๋ค.
fetchData('/api/products', options).then((res) => setData(res));
}, []);
}๋ฐฉ๋ฒ 2. ๊ฐ์ฒด ๋ง๊ณ ์์๊ฐ(Primitive) ๊ทธ ์์ฒด๋ก ๋ถํดํด์ ๊ฐ์ํด๋ผ!
๋์ค์ ๋ฒํผ์ผ๋ก limit์ ๋ฐ๊ฟ ์ ์๋ (State์ ์ฐ๋๋๋) ์ ๋์ ๊ฐ์ฒด๋ผ๋ฉด? ๊ป๋ฐ๊ธฐ(๊ฐ์ฒด ์ฐธ์กฐ)๋ฅผ ํ๊ดดํ๊ณ ์์ฑ ์๋งน์ด(์ซ์, ๋ฌธ์์ด ๋ฑ ์์ ํ์
)๋ก ์ง์ ํ์ดํค์ณ์ ๊ฐ์๋ง์ ๋ฃ์ผ์ธ์.
// โ
์์๊ฐ ์ถ์ถ๋ฒ (Pro Approach 2)
function ProductList({ limit }) { // limit๋ props (์ซ์ ํ์
)
const [data, setData] = useState(null);
// ๊ฐ์ฒด๋ฅผ ๋ ๋๋ง ๋ด๋ถ์ ์ ์ธํ์ง ๋ง๊ณ ๋ฆฌํฐ๋ด๋ก ์งํฌ์
useEffect(() => {
fetchData('/api/products', { limit: limit, sort: 'desc' })
.then((res) => setData(res));
// ๐ฏ ๊ฐ์ฒด ๊ป๋ฐ๊ธฐ๊ฐ ์๋๋ผ ๋ณํ์ง ์๋ ์์๊ฐ(์ซ์ ํ์ limit)์ ์์กด์ฑ์ผ๋ก!
}, [limit]);
}ํจ์(Functions)๋ฅผ Effect ์์์ ๋ถ๋ฅผ ๋์ ๊ท์น
ํจ์๋ ๊ฐ์ฒด์ 100% ๋์ผํ๊ฒ ์ทจ๊ธ๋์ด, ๋งค ๋ ๋๋ง๋ง๋ค ๊ป๋ฐ๊ธฐ(์ฃผ์)๊ฐ ๋ฐ๋๋๋ค. fetchProduct() ๊ฐ์ ํจ์๋ฅผ ๋ฌด์ฌ์ฝ Effect ์์์ ํธ์ถํ๊ณ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ์ผ๋ฉด ๋ฌดํ๋ฃจํ๋ฅผ ํ์ฃ .
์ด ๋๋ ๋ง๋ฅผ ํธ๋ ๊ธฐ๋ฒ์ ์์ฃผ ๋ช
ํํฉ๋๋ค.
- ์ต๊ณ ์ ๋ฐฉ๋ฒ: ์ ๋ง
useEffect์์์๋ง ์ฐ๋ ํจ์๋ผ๋ฉด, ํจ์ ์ ์ ์์ฒด๋ฅผ ์์useEffect๊ดํธ ์์ชฝ ๋ฐฉ๊ตฌ์์ผ๋ก ๋ฐ์ด ๋ฃ์ผ์ธ์. ์์กด์ฑ ๋ฐฐ์ด์ ๊ทธ ํจ์ ์ด๋ฆ์ ํต์งธ๋ก ์ ์ง ์์๋ ๋ฉ๋๋ค. - ๋ถ๋์ดํ๊ฒ ์ปดํฌ๋ํธ ๋ค๋ฅธ ๊ณณ(๋ฒํผ ํด๋ฆญ ๋ฑ)์์๋ ๊ทธ ๋ฐ๊นฅ ํจ์๋ฅผ ํธ์ถํด์ผ ํ๋ค๋ฉด? ๊ทธ๋๋ง ์ด์ฉ ์ ์์ด
useCallback์ผ๋ก ๊ป๋ฐ๊ธฐ(์ฐธ์กฐ)๋ฅผ ์ผ๋ ค๋ฒ๋ฆฌ๊ณ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ์ด์ผ ํฉ๋๋ค.
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
| ์ํฉ (๋ ๋๋ง ๊ฐฑ์ ์์ ) | โ ๋์ ๋์ | โ ์ฌ๋ฐ๋ฅธ ๋ฉํ ๋ชจ๋ธ (ํด๊ฒฐ์ฑ ) |
|---|---|---|
| ์ํ ๊ฐฑ์ ์๋ ์ ์ ๊ฐ์ฒด/ํจ์ | ๋ ๋๋ง ๋ด๋ถ์ ์ ์ธ + ๋ฌด์ ์ฃผ์ | ์ปดํฌ๋ํธ ๋ฐ๊นฅ ๊ผญ๋๊ธฐ(Module Scope)๋ก ์ด์ฌ |
| props ์ํฅ๋ฐ๋ ๋์ ๊ฐ์ฒด | ๊ฐ์ฒด ๊ป๋ฐ๊ธฐ ์ฑ๋ก []์ ๋ฐ์ | ๋ถํด(destructuring)ํ์ฌ ๊ธฐ๋ณธ ํ์
(string, number ๋ฑ ์์๊ฐ) ์์ฑ์ ์ถ์ถํด []์ ๋ฐ์ |
| ๋ฑ ํ ๊ณณ์์๋ง ์ฐ๋ ํจ์ | ํจ์ ๋ถ๋ฆฌ ํ useCallback ๋จ์ฉ | ํ์๋ก ํ๋ useEffect ๋ด๋ถ ๋ฐฉ๊ตฌ์์ผ๋ก ํจ์ ์ ์๋ฅผ ๋ฐ์ด๋ฃ์ |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
๋จ์ธ์ปจ๋, ๋ ธ๋์ lint ๊ฒฝ๊ณ (exhaustive-deps)๊ฐ ๋จ๋ฉด ๋ฌด์ ์ฃผ์์ ์น๋ ๋์ ๋น์ ์ ์ปดํฌ๋ํธ ๊ฐ์ฒด/ํจ์ ๋ถ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๋๋ฝ๋ค๋ ๊ฒ์ ์์ธํ๋ผ. ๋ฆฌ์กํธ์ ๊ฐ์๋ด์ ๊ฐ์ฒด์ ํจ์์ ๋ด์ฉ๋ฌผ์ ๊น๋ณด์ง๋ ์์ ์ฑ, ๊ทธ์ '๊ป๋ฐ๊ธฐ(ํฌ์ฅ์ง)๊ฐ ์๋ก ๋์๊ตฐ' ํ๋ฉฐ ๋ฌด์กฐ๊ฑด ์ฌ์ด๋ ์ ์ธ๋ฆด ๋ฟ์ด๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ง์ง ์ฌํ๊ป ๋ด๊ฐ ์งฐ๋ ์ฝ๋ ์ค์ ์กฐ์ฉํ ์ข๋น์ฒ๋ผ ๋ฉ์ถฐ์๋ ๋ฒ๊ทธ๋ค์ด ๋ค ์์กด์ฑ ๋ฐฐ์ด ๊ฑฐ์ง๋ง ๋๋ฌธ์ด์๋ค๋. ๋ ธ๋ ์ค ๋์ฐ๋ lint๊ฐ ๋๋ฅผ ๊ดด๋กญํ๋ ์ ๋ง์ธ ์ค ์์๋๋ฐ ์ฌ์ค ๋ด ์๋ช ์ค์ ์ก์์ฃผ๊ณ ์์๋ ๊ฑฐ๋ค.
๐ก "๋ฆฌ์กํธ์๊ฒ ๊ฑฐ์ง๋ง ์น์ง ๋ง์! ๊ฐ์ฒด ๊ป๋ฐ๊ธฐ์ ํจ์ ์ฐธ์กฐ๊ฐ์ด ๋งค๋ฒ ์๋ก ๋ถ์ด๋นต ์ฐํ๋ฏ ๋ง๋ค์ด์ง๋ ์๋ฆฌ๋ฅผ ์๋ฉด, ์์กด์ฑ ๋ฐฐ์ด์ ๋ฌด์ญ์ง ์๋ค."
๊ธฐํ์ด ๋ฐ๋๋ฉด ์ธ์ ๋ ์ง ํฐ์ง ์ํํญํ์ ๋ง๋ค๊ณ ์์๋ค๋ ์์๋์ด ๋๋ค. ๊ทธ๋๋ ์ํธ ๋ฆฌ๋ ๋์ด ์ด๋ป๊ฒ๋ ์์๊ฐ ๋ฝ์๋ด๊ฑฐ๋ ํจ์ ์์น๋ฅผ ๊น์์ด ๋ฃ์ด์ ํด๊ฒฐํ๋ ๊ฟํ์ ๋ค ์ ์ํด ์ฃผ์ จ๋ค. ์ค๋์ ๋ญ๊ฐ ๊นจ๋ฌ์์ ๋ฐ๋๊ฐ ๋๋จํ ๋์๋ค. ๊ธฐ๋ถ ์ข๊ฒ ํด๊ทผํด์ ๋ทํ๋ฆญ์ค ํ ํธ ๋๋ฆฌ๊ณ ๊ฟ์ ๊ฐ์ผ๊ฒ ๋ค!
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ์๋ ์์ฒ ์ด๊ฐ ๋ฌดํ ๋ ๋๋ง ํญํ์ ํผํ๊ธฐ ์ํด ์ง ์ฝ๋์
๋๋ค. lint์์ fetchUserData ํจ์๋ฅผ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ์ผ๋ผ๊ณ ๊ฒฝ๊ณ ํ์ง๋ง, ์์ฒ ์ด๋ ๊ทธ๋ฅ ์ฃผ์์ผ๋ก ๋ฌด์ํ์ต๋๋ค. ๊ฐ์ฅ ์ฌ๋ฐ๋ฅด๊ณ ๊น๋ํ ๋ฆฌํฉํ ๋ง ํด๊ฒฐ์ฑ
์ ๋ฌด์์ธ๊ฐ์?
function UserCard({ userId }) {
const [user, setUser] = useState();
// ๋ฐ์์ ์ ์ธํด๋ฒ๋ฆผ!
const fetchUserData = async () => {
const res = await fetch(`/api/user/${userId}`);
setUser(res);
};
useEffect(() => {
fetchUserData();
// eslint-disable-next-line
}, [userId]);
// ...
}- A)
fetchUserDataํจ์๋ฅผuseCallback์ผ๋ก ๋ฌด์กฐ๊ฑด ๊ฐ์ธ๊ณ ์์กด์ฑ ๋ฐฐ์ด์ ๋ฃ๋๋ค. - B)
fetchUserDataํจ์ ์์ฒด๋ฅผ ์์useEffect๊ดํธ ๋ด๋ถ ๊น์์ด(์ฝ๋ฐฑ ์์ชฝ์ผ๋ก) ์ด๋์ํจ๋ค. (๋ค๋ฅธ ๋ฒํผ์์ ์ด ํจ์๋ฅผ ๋๋ฅผ ์ผ์ด ์์ผ๋ฏ๋ก) - C) ๋ฌดํ ๋ฃจํ๊ฐ ๋๋๋ผ๋ ๊ฒฝ๊ณ ์ฃผ์์ ํฌ๊ธฐํ๊ณ ์์กด์ฑ์
[userId, fetchUserData]๋ฅผ ๋ชฝ๋ ๋ฃ๋๋ค. - D)
useRef๋ฅผ ๋ง๋ค์ด์ ํจ์๋ฅผ ๊ทธ ์์ ์จ๊ฒจ ๋ฃ๋๋ค.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ๊ฐ์ฅ ํํ๋ฉด์ ๊ณ ๊ทํ ํด๊ฒฐ์ฑ
์
๋๋ค. ํด๋น ํจ์๊ฐ ์ธ๋ถ ํด๋ฆญ ์ด๋ฒคํธ ๋ฑ ์ด๋ ๋ค๋ฅธ ๊ณณ์์๋ ์ฐ์ด์ง ์๊ณ ์ค๋ก์ง ๋ง์ดํธ/๋๊ธฐํ ์์ ์ ๋ฑ ํ ๋ฒ ์ Effect ์์์๋ง ๋ฐ๋๋๋ ๊ฒ์ด๋ผ๋ฉด, ๋ฐ์์ ์ธ๋ฐ์์ด ๋ฉ๋ชจ๋ฆฌ ๊ป๋ฐ๊ธฐ(์ฐธ์กฐ)๋ฅผ ์๋ก ๋ถ์ด๋นต ์ฐ์ด๋ผ ์ด์ ๊ฐ ์์ต๋๋ค. useEffect(() => { const fetchUserData = async () => { ... }; fetchUserData(); }, [userId]); ์ฒ๋ผ ์ด์ฌ์ํค๋ฉด, lint ๊ฒฝ๊ณ ๋ ์๋ฒฝํ ์ฌ๋ผ์ง๊ณ ๋ฉ๋ชจ๋ฆฌ๋ ๊น๋ํด์ง๋ฉฐ '๋ถํ์ํ useCallback ์ฐ์ฐ'๋ง์ ์๋ ์ ์์ต๋๋ค!
Q2. ์๋ฐ์คํฌ๋ฆฝํธ์ Primitive(์์) ํ์
๊ณผ Reference(์ฐธ์กฐ) ํ์
์ Effect๊ฐ ๊ฐ์ํ ๋ ๋ํ๋๋ ์ฐจ์ด๋ฅผ ๋ฌป๋ ์ง๋ฌธ์
๋๋ค. ๋ค์ ์ค useEffect์ ๊ดํธ [ ] ๋ฐฐ์ด์ ๋จ๋
์ผ๋ก ๋ฐฐ์น๋์์ ๋, ๋งค ๋ ๋๋ง ์๋ง๋ค ๋ด์ฉ๋ฌผ์ด ๊ฐ๋๋ผ๋ "๋ฐ๋์๋ค!"๊ณ ๋ฆฌ์กํธ๊ฐ 100% ์ฐฉ๊ฐํ๊ฒ ๋ง๋๋ ํ์
๋ค๋ง ๊ณ ๋ฅธ ๊ฒ์?
- A)
200,'success',false(์ซ์, ๋ฌธ์, ๋ถ๋ฆฌ์ธ) - B)
{},[],() => {}(๋น ๊ฐ์ฒด, ๋น ๋ฐฐ์ด, ํ์ดํ ํจ์) - C)
null,undefined,NaN - D) ์ด ์ค ์ ๋ต ์์ (๋ฆฌ์กํธ๋ ์๋ฒฝํด์ ์ฐฉ๊ฐํ์ง ์์)
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ์์ฃผ ์ค์ํ 0.1์ด์ ๋๋ฑ์ฑ ํ๋ณ ๋ก์ง(Object.is)์
๋๋ค. A๋ C ๊ฐ์ ์์(Primitive) ํ์
๋ค์ 200 === 200 ์ฒ๋ผ ๊ฐ ์์ฒด๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ทธ ์์ฒด์ด๋ฏ๋ก ๋ฆฌ์กํธ๊ฐ ๋ ๋๋ง ์ค๋
์ท ๊ฐ์ ์ ํ ํท๊ฐ๋ฆฌ์ง ์์ต๋๋ค. ํ์ง๋ง B์ ๊ฐ์ด ๋ฆฌํฐ๋ด๋ก ์ ์ธ๋๋ ์ฐธ์กฐ(Reference) ํ์
๋ค์ ๋ ๋๋งํ ๋๋ง๋ค ์๋ก์ด ํ(Heap) ๊ณต๊ฐ์ ๋ฐฉ์ด ํ์ง๋ฉฐ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์(๊ป๋ฐ๊ธฐ)๊ฐ ๊ต์ฒด๋๋ฏ๋ก, ๋ด์ฉ๋ฌผ์ด ๋น์ด ๋๊ฐ๋๋ผ๋ ๋ฆฌ์กํธ๋ ๋ฌด์กฐ๊ฑด false(๋ค๋ฅด๋ค) ํ์ ์ ๋ด๋ ค๋ฒ๋ ค Effect ๋ถ์์ฉ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
Q3. ์์ฒ ์ด๊ฐ "์ด์ฐจํผ ์ ๊ฐ ์ง ๊ฑฐ๋๊น ์ ๊ฐ ์ ์ผ ์ ์์์. ์ด ๊ฒฝ๊ณ ์ฃผ์(eslint-disable) ๋ฌด์ํด๋ ์ฑ ์ ํฐ์ง๊ณ ์ ๋์๊ฐ๋๋ฐ์?" ๋ผ๊ณ ์ฐ๊ธธ ๋, ์ํธ๊ฐ ์กฐ์ฉํ [categoryId] ์์กด์ฑ์ ์์ผ๋ก ๊ฐ๋ฆฌํค๋ฉฐ ์ง์ด์ค ์ ์๋ '๋ฏธ๋์ ๋ฅ์น ์ง์ง ์น๋ช
์ ์ธ ๋ฒ๊ทธ ์๋๋ฆฌ์ค'๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ์์ฑํด ๋ณด์ธ์.
โ ์ ๋ต ๋ฐ ์ฃผ๊ด์ ํด์ค:
"์์ฒ ๋, ๋น์ฅ์ ์ปดํฌ๋ํธ ์ต์ด ๋ง์ดํธ ์ ํ ๋ฒ๋ง ํธ์ถ๋์ด์ ์ ๋๋ค๊ณ ์ฐฉ๊ฐํ์๊ฒ ์ฃ . ํ์ง๋ง ๋ฏธ๋์ ๊ธฐํ์ด ๋ณ๊ฒฝ๋์ด ํ๋ฉด ์ข์ธก์ ์ฌ์ด๋๋ฐ ์นดํ
๊ณ ๋ฆฌ ๋ฒํผ๋ค(categoryId=1, 2, 3... ๋ณ๊ฒฝ)์ด ์๊ธด๋ค๋ฉด ์ด๋ป๊ฒ ๋๋์?
์์กด์ฑ ๋ฐฐ์ด์ []๋ก ๊ฐ์ ๋ก ๋๋ ค๋ด๊ณ ์ฃผ์์ ์น ์๊ฐ, ์ฐ๋ฆฌ๋ ๋ฆฌ์กํธ์๊ฒ '์ด Effect ๋ฉ์ด๋ฆฌ๋ ์ธ๋ถ ์ธ๊ณ์ ์ด๋ ํ ํ๊ฒฝ(ํ๋กํผํฐ ๋ฑ)์ด ๋ณํด๋ ์ ๋ ๋ค์ ๋๊ธฐํํ ํ์๊ฐ ์๋ค!' ๋ผ๊ณ ๊ฑฐ๋ํ ์์ฝ์ ๋งบ์ ์
์
๋๋ค.
์ฌ์ฉ์๊ฐ ๋ฐฑ๋ ๋ค๋ฅธ ์นดํ
๊ณ ๋ฆฌ๋ฅผ ๋๋ฌ์ categoryId ๊ฐ(State)์ด ๋ณ๊ฒฝ๋๋๋ผ๋, ์ด๋ฏธ ๊ท๋ฅผ ๋ซ์๋ฒ๋ฆฐ Effect๋ ๊ฒฐ์ฝ ์ API ํธ์ถ์ ๋๋ฆฌ์ง ์์ต๋๋ค (๋๊ธฐํ ๊ฑฐ๋ถ). ๊ป๋ฐ๊ธฐ UI๋ ์ ์๊ธฐ๊ธฐ ์นดํ
๊ณ ๋ฆฌ(3)๋ฅผ ๋๋ฅด๊ณ ์๋๋ฐ, ์ํ ๋ชฉ๋ก ์ ์์ํ ์ท ์นดํ
๊ณ ๋ฆฌ(1)์ ์ผ์ด๋ถ์ด ์๋ '์น๋ช
์ ์ธ ์นจ๋ฌต(Stale Data ๋ ๋๋ง) ๋ฒ๊ทธ'๊ฐ ํ์ํ๋ ๊ฒ๋๋ค."