You will learn
- effect์ ์๋ช ์ฃผ๊ธฐ์ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ์ ์ฐจ์ด
- ๊ฐ effect๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ์๊ฐํ๋ ๋ฐฉ๋ฒ
- ์ธ์ ๊ทธ๋ฆฌ๊ณ ์ effect๊ฐ ์ฌ๋๊ธฐํ ํด์ผ ํ๋์ง
- ์ด๋ป๊ฒ effect์ ์์กด์ฑ์ด ๊ฒฐ์ ๋๋์ง
- ์ด๋ค ๊ฐ์ด '๋ฐ์ํ reactive' ์ด๋ผ๋ ๊ฒ์ ์๋ฏธ
- ๋น์ด์๋ ์์กด์ฑ ๋ฐฐ์ด์ด ๊ฐ์ง๋ ์๋ฏธ
- ๋ฆฌ์กํธ๋ ์ด๋ป๊ฒ effect์ ์์กด์ฑ ๋ฐฐ์ด์ด ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฆํ๋์ง
- ๋ฆฐํฐ์ ๋์ํ์ง ์์ ๋ ์ด๋ป๊ฒ ํด์ผํ๋์ง
์ดํํธ์ ์๋ช ์ฃผ๊ธฐ
์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ๋ ๋ค์๊ณผ ๊ฐ๋ค :
- ๋ง์ดํธ : ํ๋ฉด์ ์ถ๊ฐ
- ์ ๋ฐ์ดํธ : ์ ์ ์ด๋ฒคํธ๋ ์๋ฒ์์ ํต์ ๋ฑ์ผ๋ก ์ธํ props๋ state์ ๋ณ๊ฒฝ์ด ์์ ๋ ๋ง๋ค ๋ฆฌ๋ ๋๋ง
- ์ธ๋ง์ดํธ : ํ๋ฉด์์ ์ ๊ฑฐ
๊ทธ๋ฌ๋ ์ด๋ฐ ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ์ ํ ์์์ ์ดํํธ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์๊ฐํ๋๊ฑด ์์ข์ ๋ฐฉ๋ฒ์ด(๋ผ๊ณ ํ)๋ค.
roomId๋ผ๋ prop์ ๊ฐ์ง๋ ChatRoom ์ปดํฌ๋ํธ๊ฐ ์๋ค๊ณ ํ์. ์ด ์ปดํฌ๋ํธ์ ์๋ช
์ฃผ๊ธฐ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ด๋ค :
ChatRoom์ด ๋ง์ดํธ ๋๋ค.roomId๋"general".ChatRoom์ด ์ ๋ฐ์ดํธ ๋๋ค.roomId๋ฅผ"travel"๋ก ๋ณ๊ฒฝ.ChatRoom์ด ์ ๋ฐ์ดํธ ๋๋ค.roomId๋ฅผ"music"๋ก ๋ณ๊ฒฝ.ChatRoom์ธ๋ง์ดํธ.
์ด ๊ด์ ์์ ์ฑํ ์๋ฒ์ ์ฐ๊ฒฐํ๋ ์ดํํธ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค :
- ์ดํํธ๊ฐ
"general"์ฑํ ๋ฐฉ๊ณผ ์ฐ๊ฒฐํ๋ค. - ์ดํํธ๊ฐ
"general"์ฑํ ๋ฐฉ๊ณผ์ ์ฐ๊ฒฐ์ ํด์งํ๊ณ (ํด๋ฆฐ์ )"travel"์ฑํ ๋ฐฉ๊ณผ ์ฐ๊ฒฐํ๋ค. - ์ดํํธ๊ฐ
"travel"์ฑํ ๋ฐฉ๊ณผ์ ์ฐ๊ฒฐ์ ํด์งํ๊ณ"music"์ฑํ ๋ฐฉ๊ณผ ์ฐ๊ฒฐํ๋ค. - ์ดํํธ๊ฐ
"music"์ฑํ ๋ฐฉ๊ณผ์ ์ฐ๊ฒฐ์ ํด์งํ๋ค.
๋ง์น ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋ ๋ ๋ง๋ค ์คํ๋๋ ์ฝ๋ฐฑ๊ณผ ๊ฐ๋ค๊ณ ์๊ฐ์ด ๋ ๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ์๊ฐํ๊ธฐ ์์ํ๋ฉด ๋ ๋ณต์กํด์ง๊ฒ ๋๋ค. ์ปดํฌ๋ํธ ๊ด์ ์์ ์ดํํธ๋ฅผ ์์ฑํ๋ฉด ํน์ "์์ "์ ์คํ๋์ด์ผ ํ๋์ง ์ง์ฐฉํ๊ฒ ๋๊ณ ์๋ชป๋ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋ ์ ์๋ค.
[!faq] ๋ฌด์์ด "๋ณต์กํด"์ง๋ค๋ ๊ฑธ๊น?
์ปดํฌ๋ํธ์ ๋ถ๋ฆฌํด ์ดํํธ์ ์์๊ณผ ์ค์ง ์ฌ์ดํด์ ์ง์คํ๋ฉด ์ด๋ ๊ฒ ๋๋ค :
"general"๋ฐฉ์ ์ฐ๊ฒฐ๋ ์ดํํธ"travel"๋ฐฉ์ ์ฐ๊ฒฐ๋ ์ดํํธ"music"๋ฐฉ์ ์ฐ๊ฒฐ๋ ์ดํํธ
๊ฐ ์ดํํธ๋ค์ด ๋ ๋ฆฝ์ ์ผ๋ก ์ธ์ ์ฐ๊ฒฐ๋๊ณ ์ธ์ ์ข ๋ฃํ๋์ง์ ๋ํด์๋ง ์ง์คํ๋ฉด ๊ฐ ์ฐ๊ฒฐ๋ค์ด ์ธ์ ์์๋๊ณ ์ธ์ ์ข ๋ฃ๋๋์ง์ ๋ํด์๋ง ์ค๊ณํ๋ฉด ๋๋ค.
์์ ๋ฌธ์
1,2,4 ๋ฒ ๋ฌธ์ ๋ ์๋ต.
3. stale ๊ฐ ๋ฒ๊ทธ
export default function App() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const [canMove, setCanMove] = useState(true);
function handleMove(e) {
if (canMove) {
setPosition({ x: e.clientX, y: e.clientY });
}
}
useEffect(() => {
window.addEventListener('pointermove', handleMove);
return () => window.removeEventListener('pointermove', handleMove);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
canMove๋ฅผ ๋ณ๊ฒฝํด๋ ๋ง์ฐ์ค ํฌ์ธํฐ๊ฐ ์์ง์ด๋ ์ด์ ๋ ๋ญ๊น?
๊ทธ ์ด์ ๋ ์ดํํธ์์ ์ฐธ์กฐํ๋ handleMove ํจ์๊ฐ canMove๊ฐ ์ฐธ์ผ๋ ์ ์๋ ํจ์์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ ํจ์๋ ํด๋ก์ ์ฌ์ ๊ทธ๋ ๋ค.
๊ทธ๋์ ์์ ์์กด์ฑ ๋ฐฐ์ด์ ์ญ์ ํ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ๋ ๋๋ง๋ง๋ค ์ดํํธ๊ฐ ์คํ๋๋ฉด์ ์ต์ ์ handleMove๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ.
useEffect(() => {
window.addEventListener('pointermove', handleMove);
return () => window.removeEventListener('pointermove', handleMove);
});
ํ์ง๋ง ์ด๋ ์ต์ ์ ํด๊ฒฐ๋ฐฉ๋ฒ์ด ์๋๋ค. ์ง์ ์ ์ธ ์ฐ๊ด์ด ์๋ canMove์ํ๊ฐ ์๋ ๋ค๋ฅธ ๋ชจ๋ ์ํ๋ค์ด ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค ์์ ์ดํํธ๊ฐ ์คํ๋๋๊น.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ํด๊ฒฐํ๋๊ฒ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
useEffect(() => {
function handleMove(e) {
if (canMove) {
setPosition({ x: e.clientX, y: e.clientY });
}
}
window.addEventListener('pointermove', handleMove);
return () => window.removeEventListener('pointermove', handleMove);
}, [canMove]);
์ handleMove์ ์์กดํ๋ ๋ฐฉ์์ด ์๋๋ผ handleMove๋ฅผ ๋น๋ฐ์ํ ๊ฐ์ผ๋ก ๋ง๋ค๊ณ canMove์ํ์ ์์กดํ๋๋ก ์์ฑํ ๊น? handleMove๋ canMove์ ์๊ด ์์ด ๋ ๋๋ง ๋ ๋ ๋ง๋ค ๋ฐ๋๊ฒ ๋๋๋ฐ, ๊ทธ๋ผ ์์ ์ฝ๋์ ๋๊ฐ์ด ๊ฒฐ๊ตญ ๋ชจ๋ ๋ ๋๋ง๋ง๋ค ์คํํ๋๊ฒ์ด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
5. ์ ๋ ํธ ๋ฐ์ค ์ฒด์ธ
์๋์ ์ฝ๋์์ planet ์ ํ์์ placeList ๋ฅผ ๊ฐ์ ธ์ค๋๋ก ์์ ํด์ผ ํ๋ค.
export default function Page() {
const [planetList, setPlanetList] = useState([])
const [planetId, setPlanetId] = useState('');
const [placeList, setPlaceList] = useState([]);
const [placeId, setPlaceId] = useState('');
useEffect(() => {
let ignore = false;
fetchData('/planets').then(result => {
if (!ignore) {
console.log('Fetched a list of planets.');
setPlanetList(result);
setPlanetId(result[0].id); // Select the first planet
}
});
return () => {
ignore = true;
}
}, []);
return (
//...
์ผ๋จ planetId์ ์์กดํ๋ ์ดํํธ ํ๋๋ฅผ ๋ ์ถ๊ฐํ ์ ์๋ค.
useEffect(() => {
if (planetId === '') {
// Nothing is selected in the first box yet
return;
}
let ignore = false;
fetchData('/planets/' + planetId + '/places').then(result => {
if (!ignore) {
console.log('Fetched a list of places on "' + planetId + '".');
setPlaceList(result);
setPlaceId(result[0].id); // Select the first place
}
});
return () => {
ignore = true;
}
}, [planetId]);
์ฝ๋ ๋ฐ๋ณต์ ํผํ๊ณ ์ถ๋ค๋ฉด ์ปค์คํ ํ ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
// ์ปดํฌ๋ํธ
export default function Page() {
const [
planetList,
planetId,
setPlanetId
] = useSelectOptions('/planets');
const [
placeList,
placeId,
setPlaceId
] = useSelectOptions(planetId ? `/planets/${planetId}/places` : null);
// useSelectOptions ํ
export function useSelectOptions(url) {
const [list, setList] = useState(null);
const [selectedId, setSelectedId] = useState('');
useEffect(() => {
if (url === null) {
return;
}
let ignore = false;
fetchData(url).then(result => {
if (!ignore) {
setList(result);
setSelectedId(result[0].id);
}
});
return () => {
ignore = true;
}
}, [url]);
return [list, selectedId, setSelectedId];
}

