hooks-useEffect
โWhat is useEffect
๋ ๋๋ง ํ ์ผ๋ถ ์ฝ๋๋ฅผ ์คํํ์ฌ ์ปดํฌ๋ํธ์ ์ด๋ฒคํธ๋ฅผ ๊ฑธ๊ฑฐ๋ ์ธ๋ถ ์์คํ ๊ณผ React ๋๊ธฐํ
ํน์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ/์ธ๋ง์ดํธ ๋ ๋ ์ฑํ ์๋ฒ ์ฐ๊ฒฐ/์ค์ง
ํน์ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ๋ ๋ ์๋ฒ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
ํน์ ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ํ์๋ ๋ ๋ถ์ ๋ก๊ทธ ์ ์ก
๊ธฐ๋ณธ์ ์ผ๋ก ๋ ๋๋ง ๋๋ ๋ฆฌ๋ ๋๋ง ํ ๋๋ง๋ค ์คํ
๋ ๋๋ง ๋ ๋ React ๋ ํ๋ฉด์ ์ ๋ฐ์ดํธ ํ ํ์, useEffect ๋ด๋ถ์ ์ฝ๋๋ฅผ ์คํ
์ฆ, ๋ ๋๋ง์ด ๋ธ๋ผ์ฐ์ ์ ๋ฐ์๋ ๋ ๊น์ง, useEffect์ ์คํ์ ์ง์ฐ
โ๋ ๋๋ง์ด๋?
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ
๊ฐ ๋๋ ์ํ๋ฅผ ๊ฐ์ ธ์์ ๋ฐํ ํ, ํ๋ฉด์ ํ์ํ JSX๋ฅผ ๋ฐํ
๋ ๋๋ง ์ฝ๋๋ ์์ํ๊ฒ ๊ฒฐ๊ณผ๋ง ๊ณ์ํ๊ณ ๋ค๋ฅธ ์์ ์ ์ํํ์ง ์์์ผ ํจ
๐ ์ฌ์ฉ๋ฐฉ๋ฒ: ๊ธฐ๋ณธ ์ฝ๋ ๋ฐ ์ฃผ์ ์ฌํญ
์๋์ ์ฝ๋๋ useEffect ์ ๊ธฐ๋ณธ ์ฝ๋์ด๋ค.
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Code here will run after _every_ render
});
return <div />;
}
๋ค์์ ์ฝ๋๋ ์๋ฌ๋ฅผ ๋ฐ์์ํจ๋ค. ๋ ๋๋ง ์ค DOM ๋ ธ๋ ์์ ๊ณผ ๊ฐ์ ์์ ์ ํ๋ฉด ์๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ ๋๋ง์ด ๋๋ ํ DOM ์กฐ์์ ํด์ฃผ๋ฉด ๋๋ ๊ฒ์ธ๋ฐ useEffect ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. DOM ์ ๋ฐ์ดํธ๋ฅผ useEffect ๋ก ๊ฐ์ธ๋ฉด React๋ ํ๋ฉด์ ๋จผ์ ์ ๋ฐ์ดํธ ํ๊ณ ๋์ useEffect ๋ด๋ถ์ ์ฝ๋๋ฅผ ์คํํ๋ค.
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
if (isPlaying) {
ref.current.play(); // Calling these while rendering isn't allowed.
} else {
ref.current.pause(); // Also, this crashes.
}
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
return (
<>
<button
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src='https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'
/>
</>
);
}

๐ ์ข
์์ฑ ์ง์
๊ธฐ๋ณธ์ ์ผ๋ก useEffect๋ ๋ชจ๋ ๋ ๋๋ง ํ์ ์คํ๋๋ค.
๊ฐ์ ์ปดํฌ๋ํธ ๋ด์์ ์ด๋ค ์ํ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋๋ง์ด ๋๋ค.
์ดํํธ ๋ด๋ถ์ ํจ์๋ ๊ณ์ํด์ ํธ์ถ๋๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์ ๊ฐ์ด ๋งค๋ฒ ์คํ๋๊ธธ ์ํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๋ ๋ง๋ค.
์ด ๋ ์ข ์์ฑ์ ์ฌ์ฉํ๋ค. ์ข ์์ฑ์ ์ง์ ํ ์ ์๊ณ , ๊ธฐ๋ณธ ๋ฐฐ์ด([]) ๊ฐ์ ์ค์ ํ ์๋ ์๋ค.
์๋์ ์์ ๋ ์ข ์์ฑ์ผ๋ก ๋น ๋ฐฐ์ด([])์ ์ง์ ํ์๋ค. ๋ฐ๋ผ์, console.log('test')๋ ์ปดํฌ๋ํธ๊ฐ ์ค์ง ์ฒ์ ๋ง์ดํธ ๋ ๋์๋ง ์คํ๋๋ค.
import { useState, useEffect } from 'react';
export default function App() {
const [count, setCount] = useState < number > 0;
useEffect(() => {
console.log('test');
}, []);
return (
<>
<button
onClick={() => {
setCount(count + 1);
}}
>
Increase - {count}
</button>
</>
);
}
์๋์ ์ฝ๋๋ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ์๋ฌด๋ฐ ๋์์ด ๋ฐ์ํ์ง ์๋๋ค.
๋ฌธ์ ๋ ์ดํํธ ๋ด๋ถ์ ์ฝ๋๊ฐ isPlaying ๊ฐ์ ์์กดํ์ฌ ์ํํ ์์ ์ ๊ฒฐ์ ํ๋๋ฐ, ์ด ๊ฐ์ด ์์กด์ฑ๋ฐฐ์ด์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ข ์์ฑ ๋ฐฐ์ด์ isPlaying ์ ์ถ๊ฐํ๋ฉด ๋๋ค.
์์กด์ฑ ๋ฐฐ์ด์๋ ์ฌ๋ฌ ๊ฐ์ ๊ฐ์ด ๋ค์ด๊ฐ ์ ์๋ค.
React๋ ์ง์ ํ ๋ชจ๋ ์ข ์์ฑ์ ๊ฐ์ด ์ด์ ๋ ๋๋ง ์์ ์ ํํ ๋์ผํ ๊ฒฝ์ฐ์๋ง, ์ดํํธ๋ฅผ ๋ค์ ์คํํ๋ ๊ฒ์ Skip ํ๋ค.
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
useEffect(() => {
if (isPlaying) {
console.log('Calling video.play()');
ref.current.play();
} else {
console.log('Calling video.pause()');
ref.current.pause();
}
}, []); // >> This causes an error
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
const [text, setText] = useState('');
return (
<>
<input
value={text}
onChange={(e) => {
setText(e.target.value);
}}
/>
<button
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src='https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4'
/>
</>
);
}
์์๋ ๊ฒ
React๋ Object.is ๋น๊ต๋ฅผ ์ฌ์ฉํ์ฌ ์ข ์์ฑ์ ๊ฐ์ ๋น๊ตํ๋ค. ์ง์ ํ ์ข ์์ฑ์ด Effect ๋ด๋ถ์ ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก React๊ฐ ์์ํ๋ ๊ฒ๊ณผ ์ผ์นํ์ง ์์ผ๋ฉด ๋ฆฐํธ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
์ฌ๊ธฐ๊น์ง ์ ๋ฆฌ
useEffect(() => {
// This runs after every render
});
useEffect(() => {
// This runs only on mount (when the component appears)
}, []);
useEffect(() => {
// This runs on mount _and also_ if either a or b have changed since the last render
}, [a, b]);
ํด๋ฆฝ์
์ฝ๋
์๋์ ์ฝ๋๋ 3rd Party ์ฑํ ์๋ฒ๋ฅผ ์ฐ๊ฒฐํ๋ ์ฝ๋์ด๋ค.
useEffect(() => {
const connection = createConnection();
connection.connect();
});
์ดํํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ๋ ๋(๋ฆฌ๋ ๋๋ง ๋ ๋) ๊ณ์ํด์ ์คํ๋๊ธฐ ๋๋ฌธ์, ๋น๋ฐฐ์ด([])์ ์ข ์์ฑ์ ์ถ๊ฐํ์.
useEffect(() => {
const connection = createConnection();
connection.connect();
}, []);
ํ์ง๋ง, ์ด๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ ์ ์๋ค.
์? ๐ง
ํด๋น ์ปดํฌ๋ํธ๊ฐ ํฐ ์ฑ์ ์ผ๋ถ๋ผ๊ณ ๊ฐ์ ํ๊ณ , ํด๋น ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ํ์๋์ด ์ดํํธ๊ฐ ๋ฐ์ํ๋ค. ๊ทธ ํ, ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ํด๋ฆญํ๊ณ , ๋ค์ ์ปดํฌ๋ํธ๋ก ๋ค์ด์จ๋ค. ์ด ์ฌ์ฉ์ ๋์์์์ ์ด์๋, ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ๋๊ณ ํด์ ๋์์ ๋, ์ฑํ ์๋ฒ ์ฐ๊ฒฐ์ด ๊ณ์ ๋จ์์์ด ์์ด๊ฒ ๋๋ค๋ ๊ฒ์ ์๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ํด๋ฆฐ์ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค.
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';
export default function ChatRoom() {
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect(); // clean up
}, []);
return <h1>Welcome to the chat!</h1>;
}
React๋ Effect๊ฐ ๋ค์ ์คํ๋๊ธฐ ์ ์ ๋งค๋ฒ ํด๋ฆฐ์ ํจ์๋ฅผ ํธ์ถํ๊ณ , ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ (์ ๊ฑฐ)๋ ๋ ๋ง์ง๋ง์ผ๋ก ํ ๋ฒ ํธ์ถํ๋ค. ์ฐ๊ฒฐ์ ๋์๋ค๊ฐ ๋ค์ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅธ ๋์์ด๋ค.
๊ฐ๋ฐ ์ค์ ์ดํํธ๊ฐ ๋ ๋ฒ ์คํ๋๋ ๊ฒ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋๊ฐ
<React.StrictMode> ๋ก ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ผ๋ค๋ฉด, Effect ๋ฑ์ ๋ ๋ฒ์ฉ ์คํํ๋ค. ์ด๊ฒ์ React๊ฐ ๋ฒ๊ทธ๋ฅผ ์ฐพ๊ธฐ ์ํด์ ๊ฐ๋ฐ์ค์๋ ์๋์ ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ง์ดํธํ๋ ๊ฒ์์ ๊ธฐ์ธํ ๋์์ด๋ค. ๋๋ฒ ํธ์ถ๋์ง ์๋๋ก ํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์ดํํธ๋ฅผ ํ ๋ฒ ์คํํ๋ ๋ฐฉ๋ฒ์ด ์๋๋ผ ์ดํํธ๋ฅผ ๋ค์ ๋ง์ดํธ ํ ํ์๋ ์๋ํ๋๋ก ์์ ํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์ฆ, ํด๋ฆฐ์ ํจ์๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด๋ค.
ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋๋ฒ ํธ์ถ๋์ง ์๋๋ค.
๋ด์ฅ๋ dialog ์์์ showModal ๋ฉ์๋๋ ๋ ๋ฒ ํธ์ถํ๋ฉด ์๋ฌ ๋ฐ์
ํด๋ฆฐ์ ํจ์ ๊ตฌํ
useEffect(() => {
const dialog = dialogRef.current;
dialog.showModal();
return () => dialog.close();
}, []);
๊ตฌ๋
ํ๋ ํญ๋ชฉ์ด ์๋ ๊ฒฝ์ฐ ํด๋ฆฐ์
ํจ์์์ ๊ตฌ๋
์ทจ์
useEffect(() => {
function handleScroll(e) {
console.log(window.scrollX, window.scrollY);
}
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
์ ๋๋ฉ์ด์
์ด ์ ์ฉ๋ ๊ฒฝ์ฐ ํด๋ฆฐ์
ํจ์๋ ์ ๋๋ฉ์ด์
๊ฐ์ ์ด๊ธฐ ๊ฐ์ผ๋ก ์ฌ์ค์
useEffect(() => {
const node = ref.current;
node.style.opacity = 1; // Trigger the animation
return () => {
node.style.opacity = 0; // Reset to the initial value
};
}, []);
๋ฌด์ธ๊ฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒฝ์ฐ ์ ๋ฆฌ ํจ์๋ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ค๋จํ๊ฑฐ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฌด์
useEffect(() => {
let ignore = false;
async function startFetching() {
const json = await fetchTodos(userId);
if (!ignore) {
setTodos(json);
}
}
startFetching();
return () => {
ignore = true;
};
}, [userId]);
์ด๋ฏธ ๋ฐ์ํ ๋คํธ์ํฌ ์์ฒญ์ ์คํ ์ทจ์ ํ ์ ์๊ธฐ ๋๋ฌธ์, ๋ํ ๋คํธ์ํฌ ์์ฒญ์ด ๋ฆ์ด์ง ์ ์๊ธฐ ๋๋ฌธ์, ํด๋ฆฐ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ ์ด์ ๊ด๋ จ ์๋ ์คํ์ด ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ์ ์ดํด์ค๋ค.
์ฑ๋ฆฐ์ง
์ด ์นด์ดํฐ ์ปดํฌ๋ํธ๋ ๋งค์ด๋ง๋ค ์ฆ๊ฐํด์ผ ํ๋ ์นด์ดํฐ๋ฅผ ํ์ํ๋ค. ๋ง์ดํธ ์์๋ setInterval์ ํธ์ถํ๋๋ฐ ๊ทธ๋ฌ๋ฉด onTick์ด ๋งค์ด๋ง๋ค ์คํ๋๊ณ , 2์ฉ ์ฆ๊ฐ์ํจ๋ค.
import { useState, useEffect } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
function onTick() {
setCount((c) => c + 1);
}
setInterval(onTick, 1000);
}, []);
return <h1>{count}</h1>;
}
์์ธ
strict mode ์ธ ๊ฒฝ์ฐ React๋ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ํ ๋ฒ์ฉ ๋ค์ ๋ง์ดํธํ๋ค. ์ด๋ก ์ธํด ์นด์ดํธ๊ฐ 2์ฉ ์ฆ๊ฐ๋๋ค. ์์ธ์ ์ปดํฌ๋ํธ๊ฐ 2๋ฒ ๋ง์ดํธ ๋๋ ๊ฒ์ด ์๋๋ผ, ์ดํํธ ์คํ์์ ํด๋ฆฐ์ ํจ์๋ฅผ ์ ๊ณตํ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ
clearInterval ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํด๋ฆฐ์ ํจ์ ์ ๊ณต
import { useState, useEffect } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
function onTick() {
setCount((c) => c + 1);
}
const intervalId = setInterval(onTick, 1000);
return () => clearInterval(intervalId);
}, []);
return <h1>{count}</h1>;
}
์๋์ ์ปดํฌ๋ํธ๋ ์ ํํ ์ฌ๋์ ์ ๋ณด๋ฅผ ํ์ํ๋ค. ์ ๋ ํธ ๋ฐ์ค๋ก ์ฌ๋์ ์ ํํ ๋๋ง๋ค ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋๋ง ๋๊ณ ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ์ฌ ์ ํํ ์ฌ๋์ ์ ๋ณด๋ฅผ ํ์ํ๋ค.
์ฌ๊ธฐ์์ ๋ฒ๊ทธ๋ ์ ๋ ํธ ๋ฐ์ค์ ๊ฐ์ ์ถฉ๋ถํ ๋น ๋ฅด๊ฒ ๋ฐ๊ฟ๊ฐ๋ฉด์ ์ ํํ๋ฉด, ๋ค๋ฅธ ์ฌ๋์ ์ ๋ณด๊ฐ ํ์๋๋ ๊ฒ์ด๋ค.
import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';
export default function Page() {
const [person, setPerson] = useState('Alice');
const [bio, setBio] = useState(null);
useEffect(() => {
setBio(null);
fetchBio(person).then((result) => {
setBio(result);
});
}, [person]);
return (
<>
<select
value={person}
onChange={(e) => {
setPerson(e.target.value);
}}
>
<option value='Alice'>Alice</option>
<option value='Bob'>Bob</option>
<option value='Taylor'>Taylor</option>
</select>
<hr />
<p>
<i>{bio ?? 'Loading...'}</i>
</p>
</>
);
}
์์ธ
๋ฒ๊ทธ์ ์์ธ์ ๋๊ฐ์ ๋น๋๊ธฐ ์ฐ์ฐ์ด ์๋ก ๊ฒฝ์(race condition)ํ๊ณ ์๋ค๋ ๊ฒ์ ์๋ค.
strict mode ์ธ ๊ฒฝ์ฐ React๋ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ํ ๋ฒ์ฉ ๋ค์ ๋ง์ดํธํ๋ค. ๋ก ์ธํด ์นด์ดํธ๊ฐ 2์ฉ ์ฆ๊ฐ๋๋ค. ์์ธ์ ์ปดํฌ๋ํธ๊ฐ 2๋ฒ ๋ง์ดํธ ๋๋ ๊ฒ์ด ์๋๋ผ, ์ดํํธ ์คํ์์ ํด๋ฆฐ์ ํจ์๋ฅผ ์ ๊ณตํ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ
race condition ๋ฒ๊ทธ๋ฅผ ์์ ํ๊ธฐ ์ํด์ ํด๋ฆฐ์ ํจ์๋ฅผ ์ถ๊ฐํ๋ค.
import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';
export default function Page() {
const [person, setPerson] = useState('Alice');
const [bio, setBio] = useState(null);
useEffect(() => {
let ignore = false;
setBio(null);
fetchBio(person).then((result) => {
if (!ignore) {
setBio(result);
}
});
return () => {
ignore = true;
};
}, [person]);
return (
<>
<select
value={person}
onChange={(e) => {
setPerson(e.target.value);
}}
>
<option value='Alice'>Alice</option>
<option value='Bob'>Bob</option>
<option value='Taylor'>Taylor</option>
</select>
<hr />
<p>
<i>{bio ?? 'Loading...'}</i>
</p>
</>
);
}
๊ฐ๊ฐ์ ๋ ๋๋ง์ useEffect ์๋ ๊ณ ์ ํ ๋ณ์ ignore ๊ฐ ์กด์ฌํ๋ค. ์ฒ์ ๊ธฐ๋ณธ ๊ฐ์ false์ด๋ค. ํ์ง๋ง, ๋ค๋ฅธ ์ฌ๋์ ์ ํํ๋ ๊ฒฝ์ฐ ignore ๊ฐ์ true ๊ฐ ๋๋ค.
์ด์ ์์ฒญ์ด ์๋ฃ๋๋ ์์๋ ์ค์ํ์ง ์๊ณ , ๋ง์ง๋ง์ ์ ํํ ์ฌ๋์ ignore ๊ฐ๋ง false ๊ฐ ๋๊ณ , ํด๋น ์ฌ๋์ ์ ๋ณด๋ง ํ์ํ๋ค.
'Bob'์ ์ ํํ๋ฉด fetchBio('Bob')๊ฐ ํธ๋ฆฌ๊ฑฐ
'Taylor'๋ฅผ ์ ํํ๋ฉด fetchBio('Taylor')๊ฐ ํธ๋ฆฌ๊ฑฐ๋๊ณ ์ด์ (Bob์) ์ดํํธ๊ฐ ์ ๋ฆฌ
'Bob'์ ๊ฐ์ ธ์ค๊ธฐ ์ ์ 'Taylor' ๊ฐ์ ธ์ค๊ธฐ๊ฐ ์๋ฃ
'Taylor' ๋ ๋์ ์ดํํธ๋ setBio('์ด๊ฒ์ Taylor์ ๋ฐ์ด์ค์ ๋๋ค')๋ฅผ ํธ์ถ
'Bob' ๋ถ๋ฌ์ค๊ธฐ ์๋ฃ
'Bob' ๋ ๋๋ง์ ์ดํํธ๋ ignore ํ๋๊ทธ๊ฐ true๋ก ์ค์ ๋์๊ธฐ ๋๋ฌธ์ ์๋ฌด ์์ ๋ ์ํํ์ง ์๋๋ค. ์ค๋๋ API ํธ์ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฌด์ํ๋ ๊ฒ ์ธ์๋ AbortController๋ฅผ ์ฌ์ฉํ์ฌ ๋ ์ด์ ํ์ํ์ง ์์ ์์ฒญ์ ์ทจ์ํ ์๋ ์๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ๋ง์ผ๋ก๋ race condition์ ๋ฐฉ์งํ๊ธฐ์ ์ถฉ๋ถํ์ง ์๋ค.
AbortController๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ ๋ง์ ๋น๋๊ธฐ ๋จ๊ณ๊ฐ ์ฐ์์ ์ผ ๊ฐ๋ฅ์ฑ์ด ์๊ธฐ ๋๋ฌธ์, ignore ์ ๊ฐ์ ๋ช ์์ ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์์ ์ ์ธ ๋ฐฉ๋ฒ์ด๋ค.
React๊ฐ effect๋ฅผ ์ ๋ฆฌ(clean-up)ํ๋ ์์ ์ ์ ํํ ์ธ์ ์ธ๊ฐ
์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๋ ์์ ์ ์ ๋ฆฌ ํจ์๋ฅผ ์คํํ๋ค. ์ดํํธ๋ ๋ ๋๋ง ๋ ๋ ๋ง๋ค ์คํ๋๋ค. ๋ฐ๋ผ์ ๋ค์ ์ฐจ๋ก์ ์ดํํธ๋ฅผ ์คํํ๊ธฐ ์ ์ ์ด์ ์ ๋ ๋๋ง์์ ํ์๋ ์ดํํธ๋ฅผ ์ ๋ฆฌํ๋ค. ์ด๊ฒ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ ๋ฐฉ์งํ๋ฉฐ, ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํ๋๋ฐ ๋์์ด ๋๋ค.
์ ๋ฆฌ
์ด๋ฒคํธ์ ๋ฌ๋ฆฌ useEffect๋ ํน์ ์ํธ์์ฉ์ด ์๋ ๋ ๋๋ง ์์ฒด๋ก ์ธํด ๋ฐ์
useEffect๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ์ธ๋ถ ์์คํ (ํ์ฌ API, ๋คํธ์ํฌ)๊ณผ ๋๊ธฐํ ํ ์ ์์
๊ธฐ๋ณธ์ ์ผ๋ก useEffect๋ ๋ชจ๋ ๋ ๋๋ง(์ด๊ธฐ ๋ ๋๋ง ํฌํจ) ํ์ ์คํ
๋ชจ๋ ์ข ์์ฑ์ด ๋ง์ง๋ง ๋ ๋๋ง ๋์ ๋์ผํ ๊ฐ์ ๊ฐ์ง๋ค๋ฉด useEffect๊ฐ ์คํ๋์ง ์์
๋น ์์กด์ฑ ๋ฐฐ์ด([])์ ์ปดํฌ๋ํธ ๋ง์ดํ , ์ฆ ํ๋ฉด์ ์ถ๊ฐ๋๋ ๊ฒ์ ํด๋น๋จ
Strict ๋ชจ๋์์ React๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ฒ ๋ง์ดํธํ์ฌ(๊ฐ๋ฐ ์ค์ผ ๋๋ง!) Effect๋ฅผ ์คํธ๋ ์ค ํ ์คํธ
๋ค์ ๋ง์ดํธํ๋ ๊ณผ์ ์์ ์ดํํธ๊ฐ ์ค๋จ๋๋ฉด ์ ๋ฆฌ ํจ์๋ฅผ ๊ตฌํํด์ผ ํ๋ค. (CleanUp)
React๋ ๋ค์ ๋ฒ์ ์ดํํธ๊ฐ ์คํ๋๊ธฐ ์ ๊ณผ ๋ง์ดํธ ํด์ ์ค์ ์ ๋ฆฌ ํจ์๋ฅผ ํธ์ถํ๋ค.
์ฝ์ด๋ณด๊ธฐ
Last updated