๐ก 07. useEffect ํ๊ดดํ๊ธฐ (3): Race Condition ๋ฐฉ์ด
๐ ๊ฐ์
๋น ๋ฅด๊ฒ ์ปดํฌ๋ํธ๋ฅผ ์ดํํ๊ฑฐ๋ ๋น๋๊ธฐ ์์ฒญ ํ์ด๋ฐ์ด ๊ผฌ์์ ๋ ์๋ ๋ฐ์ดํฐ๊ฐ ํ๋ฉด์ ๋ฎ์ด๋ฒ๋ฆฌ๋ ๋ฒ๊ทธ(Race Condition)๋ฅผ ํ๊ดดํ๋ Cleanup ๊ธฐ์ ์ ๋ฐฐ์๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ํ๋กํ์ด๋ ํญ์ ๋น ๋ฅด๊ฒ ์ ํํ ๋ A ์ ์ ์ผ๊ตด์ B ์ ์ ์ด๋ฆ์ด ๋จ๋ ๊ธฐ๊ดดํ ๋ฒ๊ทธ(Race Condition) ์์ธ์ ๊ฟฐ๋ซ์ ์ ์๋ค.
useEffect์ ๋ฐํ ํจ์์ธ ํด๋ฆฐ์ (Cleanup, ๋ท์ ๋ฆฌ) ํจ์๊ฐ ์ธ์ ํธ๋ฆฌ๊ฑฐ๋๋์ง 100% ์ดํดํ๋ค.- ๋ฌดํจํ(Ignore) ํ๋๊ทธ ํ๋๋ง์ผ๋ก ๋น๋๊ธฐ ํธ์ถ์ด ๊ผฌ์ธ ์๋ต์ ๊น๋ํ๊ฒ ๋ฌด์ํ๊ณ ๋ฐฉ์ดํ๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค.
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ: ์น๋ฆฌํ ์๊ฐ ์ด์๋จ๋ ๊ฒฝ์ฃผ (Race Condition)
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ํด๋ฆฐ์ (Cleanup): ํ๋๊ทธ ๊ธฐ๋ฒ์ ์๋ฆ๋ค์
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 10๋ถ / ํต์ฌ ํํธ: 6๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์(๋์์ด๋): "์์ฒ ์จ! ์ ์ ํ๋กํ ์นด๋์์ '์ฒ ์'๋ฅผ ๋๋ ๋ค๊ฐ ๊ณง๋ฐ๋ก '์ํฌ'๋ฅผ ๋๋ ๋๋ฐ... ํ๋ฉด์ ์ํฌ ์ฌ์ง ๋ฐ์ ์ฒ ์ ์ด๋ฆ์ด ๋ ์! ๊ท์ ๋ค๋ฆฐ ๊ฑฐ ์๋์์?"
- ์ํธ(๋ฆฌ๋): "๋์์ด๋๋, ๊ท์ ์ด ์๋๋ผ ์์ฒ ๋์ ์ฝ๋๊ฐ ๊ผฌ์ธ ๊ฒ๋๋ค. ๋น๋๊ธฐ ์์ฒญ๋ค์๊ฒ ๋ ์ด์ฑ ์ํฉ(Race Condition) ์ ์์ผ๋๊ณ ๋ท์ ๋ฆฌ๋ฅผ ์ ํด์ฃผ๋ฉด ์ด๋ฐ ๋์ฐธ์ฌ๊ฐ ๋์ฃ ."
๐ค ์ ์์์ผ ํ๋๊ฐ: ์น๋ฆฌํ ์๊ฐ ์ด์๋จ๋ ๊ฒฝ์ฃผ (Race Condition)
์ฐ๋ฆฌ๊ฐ ํ์์ useEffect๋ก API๋ฅผ ์ฐ๋ฅด๋ฉด, ๋ฆฌ์กํธ ์์์ ์ด๋ ๊ฒ ์๊ฐํ๊ธฐ ๋ง๋ จ์ด์ผ.
"1๋ฒ ์ ์ ๋๋ ์ด -> 1๋ฒ ์๋ต ์๋ค -> ๋ ๋๋ง. ์ด์ 2๋ฒ ์ ์ ๋๋ ์ด -> 2๋ฒ ์๋ต ์๋ค -> ๋ ๋๋ง."
์์๋๋ก ๋ฑ๋ฑ ๋จ์ด์ง ๊ฒ ๊ฐ์ง? ํ์ค์ ๋ชจ๋ฐ์ผ ๋คํธ์ํฌ ๋ฑ ํต์ ๋ง์ ๊ทธ๋ ์ง๊ฐ ์์.
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
์ ์ ์ ์ธํฐ๋ท ํ๊ฒฝ์ด 1๋ฒ ์์ฒญ์ ๋ณด๋ผ ๋ 3G ๊ธ์ผ๋ก ๋๋ฆฌ๊ณ (๋์ฉ๋ ์ฌ์ง), 2๋ฒ ์์ฒญ์ ๋ณด๋ผ ๋ 5G ๊ธ์ผ๋ก ๋ ์๋ค๋ ์ด(ํ ์คํธ ์กฐ๊ธ). ์์ฒ ์ด๊ฐ ์ฒ ์(1)๋ฅผ ๋๋ ๋ค๊ฐ ๋น์ ์๋๋ก ์ํฌ(2)๋ฅผ ํด๋ฆญํ๋ฉด ํ๋ฉด์ ๋๊ตฌ์ ์ ๋ณด๋ก ๋ฎ์ผ๊น?
โ ์์ฒ ์ด์ ๊ท์ ๋ค๋ฆฐ ํ๋กํ ์นด๋ ์ฝ๋
// โ ์์งํ ๋น๋๊ธฐ ํธ์ถ (Naive Approach)
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// ๐ฅ ์ด API๋ ์ธํฐ๋ท ์๋์ ๋ฐ๋ผ ์๋ต ๋์ฐฉ ์์๊ฐ ๋ค์ฃฝ๋ฐ์ฃฝ์ผ ์ ์๋ค!
let active = true;
fetchData(`/api/users/${userId}`).then(res => {
// "๋์ฐฉํ์ผ๋๊น ๋ฌด์กฐ๊ฑด setState ํด์ผ์ง!"
setUser(res);
});
}, [userId]);
if (!user) return <p>๋ก๋ฉ์ค...</p>;
return <div>{user.name} ({userId})</div>;
}์ฌ๊ฑด์ ๋ฐ๋จ์ ์ด๋ฌํฉ๋๋ค.
- ์ฌ์ฉ์๊ฐ ์ฒ ์(
userId: 1) ๋ฅผ ํด๋ฆญ! -> 1๋ฒ ์๋ฒ ํต์ ์ถ๋ฐ (์์ฒญ๋ ๊ณ ํ์ง ์ฌ์ง ๋๋ฌธ์ ๋ก๋ฉ 3์ด ๋๋ ์ด). - ์ฑ๊ฒฉ ๊ธํ ์ฌ์ฉ์๊ฐ ํ๋ฅผ ๋ด๋ฉฐ ๊ณง๋ฐ๋ก 1์ด ๋ค ์ํฌ(
userId: 2) ๋ฅผ ํด๋ฆญ! -> 2๋ฒ ์๋ฒ ํต์ ์ถ๋ฐ (๋ฐ์ดํฐ๊ฐ ๊ฐ๋ฒผ์ ๋ฐ๋ก ์์ฒญ ์๋ฃ). - ์ํฌ(2๋ฒ) ์๋ต ๋์ฐฉ ๐ ํ๋ฉด ์ํ๋ฅผ "์ํฌ"๋ก ๊ฐฑ์ ! (
setUser(์ํฌ)) - ๐ ๊ทธ๋ฐ๋ฐ... ์๊น ์ถ๋ฐํ๋ ์ฒ ์(1๋ฒ)์ ์๋ต์ด ๋๋ฐฐ๊ธฐ์ ๋ ์ด ๊ฑธ๋ ธ๋ค๊ฐ ์ด์ ์ผ(3์ด ๋ค์) ํ๋ ๋ฒ๋ก ๋์ฐฉ! ๐ "์ค, ๋๋ ๋ฐ์ดํฐ ๊ฐ์ ธ์์ด!" ํ๊ณ ํ๋ฉด ์ํ๋ฅผ ๋ฌด์๋นํ๊ฒ "์ฒ ์"๋ก ๋ฎ์ด์์! (
setUser(์ฒ ์))
์ ์ ๋ ์ํฌ๋ฅผ ๋๋ฅธ ์ํ์ธ๋ฐ, ๋์ง๋ง์ด ์ง๊ฐ ๋์ฐฉํ ์๋ ๋ฐ์ดํฐ(์ฒ ์)๊ฐ ํ๋ฉด์ ๋ฎ์ด๋ฒ๋ฆฐ ๊ฑฐ์ผ. ์ด๊ฒ ํ๋ก ํธ์๋ ๋น๋๊ธฐ์ ๊ฐ์ฅ ๋์ฐํ ์ , **๊ฒฝ์ ์ํ(Race Condition)**์ผ.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์๋ง(๋ฆฌ์กํธ)๊ฐ ํผ์์ง์ ์ ํ๋ฅผ ๊ฑธ์์ด. "์ฌ๋ณด์ธ์, ํํผ๋ก๋ ํ ํ์ด์!"(1๋ฒ ์์ฒญ)
๊ทผ๋ฐ 5๋ถ์ด ์ง๋๋ ๋ฐฐ๋ฌ์ด ์ ์์ ๋ต๋ตํด์ง ์๋ง๊ฐ ์ง์ฆ์ ๋ด๋ฉฐ ๊ณง๋ฐ๋ก ๋ค๋ฅธ ํผ์์ง์ ์ ํ๋ฅผ ๊ฑธ์์ด. "์ํด ์ทจ์์ทจ์, ๊ทธ๋ฅ ์น์ฆ ํผ์ ํ๋์!"(2๋ฒ ์์ฒญ)
์ด์ ๋ฐฐ์ก์ธ ์น์ฆ ํผ์๊ฐ ๋จผ์ ๋์ฐฉํด์ ๋ง์๊ฒ ๋จน๊ณ ์๋๋ฐ...(ํ๋ณตํ ํ๋ฉด)
๊ฐ์๊ธฐ ํ ์๊ฐ ๋ค์ ๋ค ์์ด๋น ์ง ํํผ๋ก๋ ํผ์ ๋ฐฐ๋ฌ์์ด ๋ฌธ์ ์พ ์พ ๋๋๋ฆฌ๋ฉฐ ๋ฌด์์ ์น์ฆ ํผ์๋ฅผ ๋นผ์๊ณ ๊ทธ๊ฑธ ์ํ ์์ ์ฌ๋ ค๋ฒ๋ ค!
"์ด? ์ด๊ฑด ์ฐ๋ฆฌ๊ฐ ์ง๊ธ ์ํ๋ ํผ์๊ฐ ์๋๋ฐ์?!" ๋ฐํญ๋ ๋ชปํ๊ณ ์ํ(ํ๋ฉด)์ด ์ ๋ น๋นํ์ง.๋ถ๋ชจ๋(๊ฒฝํ ๋ง์ ๊ฐ๋ฐ์)์ ์ ํํ ๋ ์ด๋ป๊ฒ ํ ๊น? ์น์ฆ ํผ์ ์์ผฐ์ ๋, ์ด์ ์ ๋ถ๋ ๋ ํํผ๋ก๋ ๋ฐฐ๋ฌ์์ ํฅํด **"์ผ!! ์ฐ๋ฆฌ ๋ฐฉ๊ธ ์ทจ์ํ์ผ๋๊น ๋๋ ํผ์ ๋์๋ ๊ฐ์ ธ์ค์ง ๋ง๊ณ ๋ฌด์ํด(Ignore) ๋์๊ฐ!"**๋ผ๊ณ ์ฒ ์ ํ๊ฒ ๋ท์ ๋ฆฌ(Cleanup) ์ ํ๋ฅผ ํ ํต ๋๋ ธ๊ฒ ์ง.
โ
ํต์ฌ ์๋ฆฌ:
๋ฆฌ์กํธ useEffect ์์ชฝ์ return () => {} ์ฝ๋๋ ์ ์ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ ๋๋ง ์คํ๋๋ ๊ฒ ์๋์ผ.
์ํ ์กฐ๊ฑด([userId])์ด ๋ฐ๋์ด์ ์๋ก์ด ๋๊ธฐํ(์๋ก์ด Effect)๊ฐ ๋ฎ์ด์์์ง๊ธฐ ์ง์ ์, ๋ฆฌ์กํธ๋ ํญ์ ๋ฌด์กฐ๊ฑด ์ด ํด๋ฆฐ์
๋ท์ ๋ฆฌ ์ฝ๋๋ฅผ ๋จผ์ ์คํ์์ผ ์ค.
์ด ์๊ฐ์ "์๊น ์ถ๋ฐํ๋ ๋น๋๊ธฐ ์์ฒญ์ ๋ฌธ๋งฅ์ ๋ฌด์ํด๋ฒ๋ ค๋ผ" ๋ผ๊ณ ์ ์ธํด ๋ฒ๋ฆฌ๋ฉด ๋ง์ฌ ํด๊ฒฐ!
๐งฉ ํด๋ฆฐ์ (Cleanup): ํ๋๊ทธ ๊ธฐ๋ฒ์ ์๋ฆ๋ค์
์ด ๊ท์ ๊ฐ์ ๋ ์ด์ค ์ปจ๋์
์ ๋ง๋ ๊ฐ์ฅ ์์ด์ ์ด๋ฉด์ ๊ฐ์ฅ ์๋ฒฝํ 5๋
์ฐจ์ ํจํด์ด ์์ด.
API ์์ฒด๋ฅผ ์ค๋จ(AbortController)์ํค๋ ๋ฐฉ๋ฒ๋ ํ๋ฅญํ์ง๋ง, ์ฝ๋ ๋ธ๋ก์ ์ ์ดํ๋ ๋จ์ํ boolean ๊น๋ฐ(ํ๋๊ทธ) ๊ธฐ๋ฒ์ด ๊ฐ๋
์ฑ์ด ๊ทน๊ฐ์ด์ง.
โ
์ํธ์ ๋ฆฌํฉํ ๋ง: ignore ๊น๋ฐ ํ๋ค๊ธฐ
// โ
๋ฐฉ์ด์ ์ธ ๋๊ธฐํ ์ฝ๋ (Pro Approach)
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// 1. ๋ฐฉ๊ธ ๋ด๊ฐ ํ๋์ ์ด ์ค๋
์ท ์ธ๊ณ๊ด์์, ๋๋ ์ ํจํ๋ค. (true)
let ignore = false;
async function fetchProfile() {
const res = await fetchData(`/api/users/${userId}`);
// 3. ์๋ฒ ์๋ต์ด ๋์ฐฉํ์ ๋, ๋๊ตฐ๊ฐ ๋ฐ์์ ๋๋ฅผ ๋ฌดํจํ(true)
// ์ํค์ง ์์์ ๋์๋ง ํ๋ฉด์ ๋ฎ์ด์์ฐ๋ ๊ฑธ ํ๋ฝํ๋ค!
if (!ignore) {
setUser(res);
}
}
fetchProfile(); // ๐ฅ ์ถ๋ฐ!
// 2. ํ์ง๋ง userId๊ฐ 1์์ 2๋ก ๋ฐ๋๊ฑฐ๋ ์ปดํฌ๋ํธ๊ฐ ๊บผ์ง๋ ๋ฑ,
// "๊ณผ๊ฑฐ์ ๋๊ธฐํ ์ค๋
์ท ์ธ๊ณ๊ด"์ด ๋ถ์์ง๋ ์๊ฐ ์ด ์ฒญ์๋ถ(Cleanup)๊ฐ ์ถ๋ํฉ๋๋ค.
return () => {
ignore = true; // "์ด์ด! ์๊น ๋ ๋ ํํผ๋ก๋ ๋ฐฐ๋ฌ์! ๋ ๋์์ฌ ๋ ๋ฌด์์ฒ๋ฆฌํ ๊ฑฐ๋๊น ๋ค ์์ ๊ฑฐ ์ธํ
ํ์ง ๋ง!"
};
}, [userId]); // ๊ธฐ์ค: userId
if (!user) return <p>๋ก๋ฉ์ค...</p>;
return <div>{user.name} ({userId})</div>;
}์ด์ ์ฒ ์(1)๋ฅผ ๋๋ฅด๊ณ ๋น์ ์๋๋ก ์ํฌ(2)๋ฅผ ํด๋ฆญํ๋ ์๊ฐ์ ํ๋ฆ์ ์ชผ๊ฐ๋ณผ๊ฒ.
- ์ฒ ์(1) ๋ ๋๋ง ->
ignore1 = false์ ์ธ. ์๋ฒ ์ถ๋ฐ! (3์ด ๊ฑธ๋ฆผ) - ์ํฌ(2) ํด๋ฆญ -> ๋ฆฌ์กํธ: "์ด? ๊ท์น์ด ์ํฌ๋ก ๋ฐ๋์๋ค! ์ ๊น, ๊ทธ์ ์ ์ฒ ์ ๋ ๋จ๊ฒจ๋ ์ฐ๊บผ๊ธฐ๋ถํฐ ํด๋ฆฐ์ (์ฒญ์)ํ๋ค!"
- ์ฒ ์์ ํด๋ฆฐ์
๋ฐ๋! ๐
ignore1 = true๋ก ๋ณ๊ฒฝ๋จ. (์ฒ ์ ๋ฐฐ๋ฌ์ ๋ฌดํจํ!!) - ์ํฌ(2) ๋ ๋๋ง ->
ignore2 = false์ ์ธ. ์๋ฒ ์ถ๋ฐ! (1์ด ๊ฑธ๋ฆผ, ๋จผ์ ๋์ฐฉ, ํ๋ฉด์ ์ํฌ ์ธํ ) - ๋๋์ด ์ฒ ์(1) 3์ด ๋ค ์ง๊ฐ ๋์ฐฉ. ํ์ง๋ง
if (!ignore)๋ฃธ์ ๋ค์ด๊ฐ๋ ค๋ ์ฐฐ๋, ์ด ๊ณผ๊ฑฐ์ ๊ฐ์ฅ์ ๊ฐํ ์ฒ ์ ์ธ๊ณ๊ด์ignore1์ ์ด๋ฏธ 2๋ฒ ์คํ ์์true๋ก ๋ฐ๋์ด ์์ง! - "์... ๋ฌด์๋นํ๊ตฐ." (์ํ ์ ๋ฐ์ดํธ ๋ฌด์ฐ, ์์ ๋นต ์ ์ง โ )
์ด๊ฒ์ด ๋ฆฌ์กํธ ๋์์ธ ์ฒ ํ์ด ์ ์ฌํ๋ ๊ฐ์ฅ ์ง๊ด์ ์ด๊ณ ์๋ฒฝํ ์๋ ๋ฐ์ดํฐ ๋ฐฉ์ด ๊ธฐ๋ฅ์ด์ผ.
๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
โ Cleanup์ ์ฐ์ง ์์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฒ๊ทธ(Memory Leak)
์ธ์ ๋์ค๋๊ฐ?
# ๊ฐ๋ฐ์ ๋๊ตฌ ์ฝ์์ ๋นจ๊ฐ ๊ฒฝ๊ณ ์ฐฝ
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.**์์ธ:**๋ชจ๋ฌ์ฐฝ ์์์ 10์ด์ง๋ฆฌ API ํต์ ์ ๋ ๋ ธ์ด. ๊ทผ๋ฐ ์ ์ ๊ฐ 2์ด ๋ง์ [X] ๋ฒํผ์ ๋ซ์๋ฒ๋ ค์ ๋ชจ๋ฌ ์ปดํฌ๋ํธ ์ ์ฒด๊ฐ ํญํ(Unmount)๋์ด!
๊ทธ๋ฐ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋์์๋ 10์ด ๋ค์ API ๋ฐ์ดํฐ๊ฐ ๋ฌด์ฌํ ์๋ฒ์์ ๋จ์ด์ ธ ๋์์๊ณ , ์ฃฝ์ด ์์ด์ง ๋ฌด๋ค(๋ชจ๋ฌ์ฐฝ์ setState)์ ๋๊ณ ์ฟ๋์ง์ ํ๋ฉฐ ์ํ๋ฅผ ๋ฐ๊พธ๋ ค๊ณ ํ๋๊น ๋ฆฌ์กํธ๊ฐ ๊ธฐ๊ฒ์ ํ๋ฉด์ "์, ์ด๋ฏธ ์ฃฝ์ ์ ์ก๊ณ ํ๋ค์ง ๋ง! ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ด ๋ฌ์ด!" ๋ผ๊ณ ๋ถ์ ๊ฒฝ๊ณ ์ฐฝ์ ์์ฐ์ฑ์น๋ ๊ฑฐ์ผ.
ํด๊ฒฐ์ฑ
:
๋ณธ ๊ฐ์ด๋์ ์ํธ๊ฐ ์ง ์ฝ๋์ฒ๋ผ return () => { ignore = true; } ๋ฅผ ๊ผฌ๋ฐ๊ผฌ๋ฐ ์ถ๊ฐํด! ์ปดํฌ๋ํธ๊ฐ ํญํ๋ ๋ ํด๋ฆฐ์
์ด ์ฐ์ ๋ฐ๋๋์ด ignore ๋ฅผ ๋ฐ๊พธ๋๊น, ๋ง๋ น์ด ๋๋์์๋ ์์ ํ๊ฒ ๋ฌด์๋ผ. (์ฐธ๊ณ : React 18+ ๋ฒ์ ์์ StrictMode ๋ฑ์ด ๊ฐ์ ๋์ด ๊ฒฝ๊ณ ๊ฐ ๋ ๋์ค๊ธด ํ์ง๋ง, ์์ ์ค๊ณ์ ๊ทผ๊ฐ์ ๋์ผํด)
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
| ์ํฉ | โ ๋์ ๋ฉํ (๋ฐฉ๊ด) | โ ํ๋ก์ ๋ฉํ (ํต์ /๋ฌด์) |
|---|---|---|
| ์ฐ์ ํด๋ฆญ ๋น๋๊ธฐ ์ํฉ | "์ ์ฐฉ์ ๋์ฐฉ์์ผ๋ก ํ๋ฉด ๋ฐ์ด๋ผ ๊ฑด๋ฐ ์์์ ๋๊ฒ ์ง" | "์ต์ ํด๋ฆญ(ID) ์๋ต ์ค๋
์ท๋ง ์ด๋ ค๋๊ณ ์๊น ์ถ๋ฐํ ์ข๋น ํต์ ์ ๋ฐ์ดํฐ๋ ignore ๊น๋ฐ๋ก ์ปท์์(Cut-out) ์ํจ๋ค" |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
๋น๋๊ธฐuseEffect์์return () => { ์น์ฐ๊ธฐ }๋ฅผ ๋นผ๋จน๋ ๊ฒ์, ํ์ฅ์ค์ ์ฌ์ฉํ๊ณ ๋ณ๊ธฐ ๋ฌผ์ ๋ด๋ฆฌ์ง ์๋ ์ง๊ณผ ์๋ฒฝํ๊ฒ ๋์ผํ ์ธํ๋ผ ํ๋ฝ ํ์๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์์ ์ ์ฝ์์ ๋นจ๊ฐ์์ผ๋ก '์ฃฝ์ ์ปดํฌ๋ํธ์ setState ํ์ง ๋ง!' ๊ฒฝ๊ณ ๋ด์ ๋ ๋ญ ์๋ฆฐ์ง ๋ชฐ๋ผ์ ๋ฌด์ํ์๋๋ฐ... ํผ์ ๋ฐฐ๋ฌ ๋น์ ๋ฅผ ๋ฃ์๋ง์ ๋ด๊ฐ ๋ด ์ฝ๋ํํ ๋ฌด์จ ํญ๋ ฅ์ ์ ์ง๋ ๋์ง ๋ช ํํด์ก๋ค. Race Condition์ด๋ผ๋ ์ฉ์ด๋ ์ด์ ์๋ฒฝํ ์ฐฐ๋ก๊ฐ์ด ์ดํด๊ฐ๋ค.
๐ก "๋น๋๊ธฐ ๊ฒฝ์ฃผ(Race Condition)๋ฅผ ์กฐ์ฌํ๋ผ! ๋น ๋ฅธ ํด๋ฆญ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์ดํํ ๋ Cleanup์์
ignoreํ๋๊ทธ ํ๋๋ง ๊ฝ์์ฃผ๋ฉด ์๋ฒฝ ๋ฐฉ์ด๊ฐ ๋๋ค."
์์ ๋์์ด๋๋์ด ๊ท์ ๋ค๋ฆฐ ํ๋ฉด ์ข๋น ๊ฐ๋ค๊ณ ํ์ ๋ ์ฐ๋ํ๋๋ฐ, ์ด์ ๋ ์ฐ์ํ๊ณ ํผํผํ ๋ฐฉ์ด๋ง์ ์น ์ ์๊ฒ ๋๋ค. ํด๋ฆฐ์
์ ํ๋ ๊ฒ ๋ณ๊ธฐ ๋ฌผ ์ ๋ด๋ฆฌ๋ ๊ฑฐ๋ ๋๊ฐ๋ค๋... ์ํธ ๋ ํฉํญ ๋๋ถ์ ์ค๋ ๋ด ์ฝ๋๊ฐ ํจ์ฌ ์์์ ์ผ๋ก ๋ณํ๋ค. ๊ธฐ๋ถ ์ข๊ฒ ํด๊ทผ! ์งํ์ฒ ์์ AbortController ํ๋ฒ ํ์ด๋ณด๊ณ ๊ฐ์ผ์ง.
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. useEffect์ Cleanup(๋ฐํ ํจ์) ์ฝ๋๊ฐ ์ ํํ ๋ฐ๋๋๋ ๋ ๊ฐ์ง ์๊ฐ(Timing)์ ๊ฐ์ฅ ์ ์์ ํ ๊ฒ์?
- A) ์ค์ง ๋ธ๋ผ์ฐ์ ์ฐฝ(ํญ)์ ์์ ํ ์ข ๋ฃํ ๋๋ง / ์ฌ์ฉ์๊ฐ ์๋ก๊ณ ์นจ ํค๋ฅผ ๋๋ฅผ ๋.
- B) ์ปดํฌ๋ํธ๊ฐ ์ต์ด ํ๋ฉด์ ๋ ์์ง ๋ / ์ปดํฌ๋ํธ ์์ ์๋ ์ผ๋ฐ ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋.
- C) ํด๋น ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์์ ์์ ํ ์ฌ๋ผ์ง(Unmount) ๋ / ๊ทธ๋ฆฌ๊ณ ! ๋ค์ ๋ ๋๋ง ์ฌ์ดํด์ ์ํด ํด๋น Effect๊ฐ ๋ค์ ํธ๋ฆฌ๊ฑฐ(์ฌ์คํ) ๋๊ธฐ ์ง์ .
- D) ์ฌ์ฉ์๊ฐ ์ฝ์ ๋ก๊ทธ๋ฅผ ๊ฐ์ํ๊ณ ์์ ๋ / ๊ฐ์ ๋ก React Garbage Collection์ ํธ์ถํ ๋.
โ ์ ๋ต: C
๐ก ์์ธ ํด์ค: ์ด๊ฒ Cleanup์ ์นํธํค ์๋ฆฌ์
๋๋ค. ๋จ์ํ ์ปดํฌ๋ํธ๊ฐ ์ฃฝ์ ๋(Unmount) ๋ง ๋ท์ ๋ฆฌ๋ฅผ ํ๋ ๊ฒ ์๋๋๋ค! ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ๋๋ฌ ์ํ ๊ฐ์ด ๋ฐ๋์ด [userId] ์์กด์ฑ์ด ๋ฌ๋ผ์ง๋ฉด, ๋ฆฌ์กํธ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ก ๋๊ธฐํ๋ฅผ ์ํค๊ธฐ ์ํด ๋ฐ๋์ ๊ณผ๊ฑฐ์ ์ค๋
์ท ํ์ ์ ์ป์ด๋ด๋ Cleanup ๋ถํฐ ๋จผ์ ํ ๋ฒ ์คํ ํ ๋ค, ๊ทธ์ ์ผ ์๋ก์ด Effect ๋ณธ๋ฌธ์ ๋๋ฆฝ๋๋ค. ์ด ์๋ฆฌ ๋๋ฌธ์ ๋ณ์๋ฅผ ignore = true ๋ก ๋ฐ๊ฟ์ ์ด์ ์์ฒญ์ ํ๊ธฐ์ํค๋ ํ๋๊ทธ ๊ธฐ๋ฒ์ด ์ฐ์ํ๊ฒ ์๋ํ๋ ๊ฒ์
๋๋ค!
Q2. ๋ค์ ์ค Race Condition(๋น๋๊ธฐ ๊ฒฝ์ ์ฐธ์ฌ)์ด ๊ฐ์ฅ ์ฌํ๊ฒ ๋ฐ์ํ ์ ์๋ ์ทจ์ฝํ ์กฐ๊ฑด์ ๊ฐ์ถ UI ์ํฉ์ ์ด๋ค ๊ฒ์ธ๊ฐ์?
- A) ์ ์ ๊ฐ ์ฅ๋ฐ๊ตฌ๋์ ์ํ ์ญ์ ๋ฒํผ์ ํ ๋ฒ ํด๋ฆญํ ๋ค ํ๋ฉด์ด ๋ฐ๋ก ๋ก๋ฉ(Spinning) ์คํฌ๋ฆฐ์ผ๋ก ์ ๊ธฐ๋ ํ๋ฉด.
- B) ์ค์๊ฐ์ผ๋ก ์ด๋น 5๊ฐ์ฉ ๋ฐ๋๋ "๊ด์ฌ ์ฃผ์ ์ข ๋ชฉ(ํญ)" ๋ฆฌ์คํธ๋ฅผ ๋๋๋ค๋ฉฐ ์ข ๋ชฉ์ ์ฐจํธ ๊ทธ๋ํ ๋ฐ์ดํฐ๋ฅผ API๋ก ์ด์ ๊ทธ๋ ค์ฃผ๋ ํ๋ฉด.
- C) ์ฒ์์ ๋ฑ ํ ๋ฒ 50MB์ง๋ฆฌ ํต๊ณ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ ํ๋ฉด ์ค์์ ๋ฐ์๋ฒ๋ฆฌ๋ ๋ฉ์ธ ํ์ด์ง ํ๋ฉด.
- D) ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ด๋ถ State ์ซ์๋ง
count + 1ํ๋๋ก ์กฐ์๋ ํ ์คํธ ์นด์ดํฐ ํ์ด๋จธ ํ๋ฉด.
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค: ํญ ์ ํ์ด๋ ์ค์๊ฐ ํ์ดํ(์๋์์ฑ ๊ฒ์ UI)์ฒ๋ผ ์ฌ์ฉ์๊ฐ ์์ฒญ๋๊ฒ ๋น ๋ฅธ ์๋๋ก ํค ์ ๋ ฅ์ด๋ ํญ ํด๋ฆญ์ ์กฐ๊ฑด์ ๊ณ์ ๋ณํ์ํฌ ๋, ๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ๋ค์ด ์ ๋ถ ๋คํธ์ํฌ ์ง์ฐ(Latency)์ด ๋๋ฐ๋๋ ๋ฌด๊ฑฐ์ด ์๋ฒ API ์์ฒญ์ผ ๋ ์ด๋ง์ด๋งํ ๋น๋๊ธฐ ์ง์ฅ์ ๋ ์ด์ค ์ปจ๋์ ๋ค์ด ์ฐ์ถ๋ฉ๋๋ค. 2๋ฒ ํญ์ ์๋ฒ์์ฒญ์ ๋ฒ๊ฐ์ฒ๋ผ ์๋๋ฐ, ์๊น ๋๋ฅธ 1๋ฒ ํญ์ ์์ญ MB ์ด๋ฏธ์ง๊ฐ 5์ด ๋ค์ ๋ฉ์ฒญํ๊ฒ ํ๋ฉด์ ์พ ๋ฎ์ด๋ฒ๋ฆฌ๋๊น์! Cleanup ๋ฌดํจํ ์ฒ๋ฆฌ๊ฐ ๋ฐ๋์ ํ์ํ ๊ณณ์ ๋๋ค.
Q3. useEffect ์ธ๋ถ ํต์ ์ ์บ์ฌํ๋ ๋ ๊ฐ๋ ฅํ ๋ฌด๊ธฐ์ธ ๋ธ๋ผ์ฐ์ ๋ด์ฅ API AbortController ์ ๋ํด ๋ค์ด๋ณธ ์ ์ด ์์ ๊ฒ๋๋ค. ์ด API๋ฅผ ์ด์ฉํ ํด๋ฆฐ์
์๋๋ฆฌ์ค์, ์ํธ๊ฐ ์ด ๋น ๋ณ์(ํ๋๊ทธ) let ignore = false ํธ๋ฆญ ๊ฐ์ ์ค์ง์ ์ฑ๋ฅ(๋คํธ์ํฌ ๋ ๋ฒจ) ์ฐจ์ด๋ ๋ฌด์์ผ๊น์? ์ฃผ๊ด์์ผ๋ก ๊ฐ๋ตํ ํต์ฐฐ์ ์จ๋ณด์ธ์.
โ ์ ๋ต ๋ฐ ์ฃผ๊ด์ ํด์ค:
์ฃผ๊ด์ ํด์ค ์๋ฆฌ:
๊ฐ์ฅ ํฐ ์ฐจ์ด๋ ๋ง์ด ์๋ชจ๋๋ ์์์ ์ค๋จ(Cancel) ์ฌ๋ถ์
๋๋ค. ์ํธ๊ฐ ๊ฐ๋ฅด์ณ์ค let ignore = false ๋ณ์ ํธ๋ฆญ์ ์ฝ๋๊ฐ ์ง๊ธฐ ์ฝ๊ณ ๋ฌด๋ํ๊ฒ ์ธ ์ ์์ง๋ง, ์ผ๋จ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒซ ํํผ๋ก๋ ๋ฐฐ๋ฌ์์ ์ถ๋ฐ์์ผฐ๋ค๋ฉด ๋ฐฐ๋ฌ์ ์์ฒด์ ํธ๋ํฝ ์ด๋(์๋ฒ ๋ฐ์ดํฐ ๋ค์ด๋ก๋)์ ๋ง์ง๋ ๋ชปํฉ๋๋ค. ๊ทธ์ ๋ฐ์ดํฐ ํต์ ์ด ๋๋์ ์ง์ ๋๋ฌํ์ ๋ ์์ฝํ๊ฒ ๋ฌธ์ ์ ์ด์ด์ฃผ๊ณ ํ๋ฉด ์
๋ฐ์ดํธ(setState)๋ง ๋ฌด์ํ ๋ฟ์ด์ฃ (์์ ๋ง ํ๋ณด).
ํ์ง๋ง ๋ธ๋ผ์ฐ์ ์์ฒด ์ง์ API์ธ AbortController.abort() ๋ฅผ ํด๋ฆฐ์
์ ๋ฌผ๋ ค ๊ตฌํํ๋ฉด? ๋ฆฌ์กํธ๊ฐ ๋ฐฐ๋ฌ์์ด ์ถ๋ฐํ๊ณ ์ค๊ฐ์ฏค ์ง๋ฌ์ ๋ "์ผ! ๋ฐฐ์ก ์ค์งํด ํต์ ์ ๋์ด๋ฒ๋ ค(Network Cancel)!" ๋ช
๋ น์ ๋ธ๋ผ์ฐ์ ๋ง์๋ค ๊ฝ์๋ฒ๋ฆฝ๋๋ค. ํฌ๋กฌ ๋คํธ์ํฌ ํญ์ ๋นจ๊ฐ์(canceled) ์๋ฌ ์ฐฝ์ด ์์๊ฒ ๋จ๋ฉด์, ๋ฐ์ดํฐ ๋ญ๋น ํธ๋ํฝ ์์ฒด๋ฅผ ์ค๊ฐ์ ์๋ฉธ์ํค๋ฏ๋ก ์ฑ๋ฅ์ ์ผ๋ก ๊ฐ์ฅ ์ด์์ ์ธ ๋๊ธฐ์
๋ง์ธ๋(๊ณ ์ฑ๋ฅ) ํด๊ฒฐ์ฑ
์ด ์์ฑ๋ฉ๋๋ค! (๋ ๋ค ๋ฌดํ ๋ฐ์ดํฐ ๋ฐฉ์ด ํจ๊ณผ๋ ๊ฐ์ต๋๋ค.)