[๐Ÿšจ Error ๐Ÿšจ] useEffect ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์‚ฌ์šฉ

์šฐํ˜ยท2024๋…„ 2์›” 15์ผ

๐Ÿšจ Error ๐Ÿšจ

๋ชฉ๋ก ๋ณด๊ธฐ
3/11

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ฐฐ๊ฒฝ

useEffect์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ธ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋‹ˆ๊น ์—๋Ÿฌ ๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ์ƒํ™ฉ
โ†ช (์ง€๊ธˆ ๋‹น์žฅ ๊ฒฐ๊ณผ์— ๋ฌธ์ œ๋Š” ์—†์ง€๋งŒ ํ„ฐ๋ฏธ๋„ ์ฐฝ๊ณผ ์ฝ˜์†” ์ฐฝ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋‹ค!)

ํ„ฐ๋ฏธ๋„ ์ฐฝ eslint ๊ฒฝ๊ณ 

  • ๐Ÿšจ Effect callbacks are synchronous to prevent race conditions

๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”์ฐฝ ์—๋Ÿฌ

  • ๐Ÿšจ must not return anything besides a function, which is used for clean-up


๋ฌธ์ œ์˜ ์›์ธ ์•Œ์•„๋ณด๊ธฐ

1. eslint ๊ฒฝ๊ณ  ๋ฌธ๊ตฌ๋ฅผ ํ•ด์„ํ•ด๋ณด๋ฉด useEffect์˜ ์ฝœ๋ฐฑ์€ ๊ฒฝ์Ÿ ์ƒํƒœ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋ผ๊ณ  ๋˜์–ด ์žˆ๋‹ค.
โ†ช ๋น„๋™๊ธฐ ์ž‘์—…์ด ํฌํ•จ๋œ useEffect ์ฝœ๋ฐฑ์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์„œ๋กœ ๊ฒฝ์Ÿํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฝ๊ณ  ๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค!

๊ฒฝ์Ÿ ์ƒํƒœ(Race Condition)
๋น„๋™๊ธฐ ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ ์ค‘ ํ•˜๋‚˜๋กœ, ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋น„๋™๊ธฐ ์ž‘์—…์ด ๋™์‹œ์— ๊ฒฝ์Ÿํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์„ ๋งํ•œ๋‹ค.

2. ์ฝ˜์†”์ฐฝ ์—๋Ÿฌ ๋ฌธ๊ตฌ๋ฅผ ํ•ด์„ํ•ด๋ณด๋ฉด ์ •๋ฆฌ(Clean-Up) ์™ธ์—๋Š” ์–ด๋– ํ•œ ๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.๋ผ๊ณ  ๋˜์–ด ์žˆ๋‹ค.
โ†ช useEffect์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์•ˆ๋˜๋Š”๋ฐ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค!


๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

useEffect์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์ธ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋˜์ง€๋งŒ, useEffect ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— useEffect ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค!

๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์„ ์–ธํ•ด์„œ ์‹คํ–‰ํ•˜๊ธฐ

useEffect(() => {
	const fetchData = async () => {
    	try{
        	const response = await fetch(url);
			if(!response.ok){
				throw new Error("API ์š”์ฒญ ์—๋Ÿฌ ๋ฐœ์ƒ!");
			}
			console.log("API ์š”์ฒญ ์„ฑ๊ณต!");
        }catch(err){
			console.error(err);
		}
	}
    fetchData();
}, [url])

๋น„๋™๊ธฐ ์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜ ์‚ฌ์šฉ

useEffect(() => {
	(async () => {
    	try{
        	const response = await fetch(url);
			if(!response.ok){
				throw new Error("API ์š”์ฒญ ์—๋Ÿฌ ๋ฐœ์ƒ!");
			}
			console.log("API ์š”์ฒญ ์„ฑ๊ณต!");
        }catch(err){
			console.error(err);
		}
	})();
}, [url])

+ useEffect๋กœ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ

useEffect ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ฐ˜๋ณตํ•˜๋ฏ€๋กœ ํด๋ฆฐ ์—…(Clean-Up) ํ•จ์ˆ˜์—์„œ ์ด์ „ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. fetch์˜ ๊ฒฝ์šฐ abortController ๋“ฑ์œผ๋กœ ์ด์ „ ์š”์ฒญ์„ ์ทจ์†Œํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค!

useEffect(() => {
	const controller = new AbortController();

	(async () => {
    	try{
        	const result = await fetch(url, { signal: controller.signal });
			setData(await result.json())
        }catch(err){
			console.error(err);
		}
	})();

	// ํด๋ฆฐ ์—…(Clean-Up) ํ•จ์ˆ˜ ์ž‘์„ฑ
	return () => controller.abort();
}, [url])

0๊ฐœ์˜ ๋Œ“๊ธ€