useEffect
ํ์ต ํค์๋
useEffect
Side Effect?
Clean-up
Effect๊ฐ ๋ ๋ฒ ์คํ๋๋ ๋ฌธ์
useLayoutEffect
๐ useEffect
Effect Hook์ ์ฌ์ฉํ๋ฉด ํจ์ ์ปดํฌ๋ํธ์์ side effect๋ฅผ ์ํํ ์ ์์ต๋๋ค. by.useEffect ๊ณต์๋ฌธ์
์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ์ดํ์ side effect(ํน์ ์์ )๋ฅผ ์ํ ํ ์ ์๋๋ก ํด์ฃผ๋ ๊ธฐ๋ฅ
Side-Effect ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ hook
๐ค Side Effect?
ํจ์ ๋ด ํน์ ๋์์ด ํจ์ ์ธ๋ถ์ ์ํฅ์ ๋ผ์ณ, ํ๋ก๊ทธ๋จ์ ๋์์ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋๋ ํ์
ํจ์๊ฐ ์คํ๋๋ฉด์ ํจ์ ์ธ๋ถ์ ์กด์ฌํ๋ ๊ฐ์ด๋ ์ํ๋ฅผ ๋ณ๊ฒฝ์ํค๋ ๋ฑ์ ํ์๋ฅผ ์๋ฏธ
์๋ฅผ๋ค์ด ํจ์๋ด์์ ์ ์ญ๋ณ์์ ๊ฐ์ ๋ณ๊ฒฝํ๊ฑฐ๋ ํน์ ํจ์ ์ธ๋ถ์ ์กด์ฌํ๋ ๋ฒํผ์ ํ ์คํธ๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋, ํ์ผ์ ์ฐ๊ฑฐ๋, ์ฟ ํค ์ ์ฅ, ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ก์ ํ๋ ๊ฒ
โ
Side Effect๋ฅผ ๊ด๋ฆฌํ๋ ์ด์
Side-Effect๋ ํ๋ก๊ทธ๋จ์ ์ฝ๊ธฐ ์ด๋ ต๊ฒ ํ๊ณ , ์คํ์ํ๋ฅผ ์์ธกํ๊ธฐ ์ด๋ ต๊ฒ ํ๋ฉฐ ๊ฐ๋ฐ๋น์ฉ์ ์ฆ๊ฐ์ํจ๋ค๊ณ ๋ณด๊ธฐ ๋๋ฌธ์ ์ต๊ทผ ์ ์ธํ ํ๋ก๊ทธ๋๋ฐ์์๋ Side-Effect๋ฅผ ์ต์ํํ๋ ๋ฐฉํฅ์ผ๋ก ๋ณํ๊ณ ์๋ค. ํจ์๋ ์ ๋ฌ๋ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ์ฐ์ฐ์ ์ํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํด์ผ ํ๋ฉฐ ๊ทธ ๊ฒฐ๊ณผ๋ ํญ์ ์ผ๊ด๋๊ณ ์์ธกํ ์ ์์ด์ผ ํ๋ก๊ทธ๋จ์ด ์ฝ๊ณ ๋จ์ํ๋ฉฐ ์ ์ง๋ณด์ ํ๊ธฐ ์ฌ์์ง๊ธฐ ๋๋ฌธ์ด๋ค.
useEffect ์ฌ์ฉ ์์
function UserProfile({ name }) {
const message = `${name}๋ ํ์ํฉ๋๋ค!`; //ํจ์ ๋ฐํ ๊ฐ ์์ฑ
// Bad!
document.title = `${name}์ ๊ฐ์ธ์ ๋ณด`; //ํจ์ ์ธ๋ถ์ ์ํธ์์ฉํ๋ Side-effect ์ฝ๋
return <div>{message}</div>;
}
function UserProfile({ name }) {
const message = `${name}๋ ํ์ํฉ๋๋ค!`;
useEffect(()=> {
document.title = `${name}์ ๊ฐ์ธ์ ๋ณด`;
},[name]);
return <div>{message}</div>;
}
โ๐ป useEffect ์ ๋ฆฌ
useEffect
๋ ์ปดํฌ๋ํธ๊ฐ ์ต๋ํ ์์ ํจ์๊ฐ ๋ ์ ์๋๋ก Side Effect๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌ ํ ์ ์๋๋ก ํ๋ค.๋งค๋ฒ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋ ํน์ ์กฐ๊ฑด์ ์์กดํ์ฌ ์ํ๋๋ฉฐ, ์ปดํฌ๋ํธ๊ฐ ์ต๋ํ ์์ ํจ์๋ฅผ ์ ์งํ ์ ์๋๋ก ๋์์ฃผ๋ ํจ์
๐ค useState ์ฌ์ฉ๋ฒ
import { useEffect } from "react"; //์ฌ์ฉ์ ์ํด import ํด์ค์ผ ํ๊ณ ,
useEffece(()=> {}, [dependency Array]) //์ฝ๋ฐฑํจ์์ ์์กด์ฑ๋ฐฐ์ด์ ์ธ์๋ก ๋ฃ์ด์ค๋ค.
useEffect๋ ํจ์์ ์ธ์(์์กด์ฑ๋ฐฐ์ด)์ ๋ณด์ ๋ฐ๋ผ ํฌ๊ฒ ์ธ๊ฐ์ง ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
๋ฌดํ๋ฐ๋ณต
์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค useEffect์ ์ธ์๋ก ์ ๋ฌํ ์ฝ๋ฐฑํจ์๊ฐ ์คํ๋๋ค.
import { useEffect, useState } from 'react';
export default function TimerControl() {
const [playing, setPlaying] = useState(false);
useEffect(() => {
console.log('๋งค๋ฒ ์คํ');
});
const handleClick = () => {
console.log('Click!');
setPlaying(!playing);
};
return (
<div>
<button type="button" onClick={handleClick}>
ํ ๊ธ ๋ฒํผ {playing ? `on` : `off`}
</button>
</div>
);
}
์ฒ์์ ํ๋ฒ๋ง ์คํํ๊ธฐ
์ด์ ์์ ์ ๋์ผํ์ง๋ง, useEffectํจ์์ ๋๋ฒ์งธ ์ธ์๊ฐ ์๊ฒผ๋ค. ๋๋ฒ์งธ ์ธ์๋ฅผ ๋น ๋ฐฐ์ด๋ก ์ ๋ฌํ๊ฒ ๋๋ฉด, ์ปดํฌ๋ํธ๊ฐ ์ต์ด ๋ ๋๋ง๋ ๋๋ง useEffect๋ฅผ ์คํํ๋ค. โ useEffect ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ํ ๋งค๋ฒ ์ฝ๋ฐฑํจ์๋ฅผ ์คํํ๋ค. ๊ทธ๋ฌ๋ ์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ด ๋น ๋ฐฐ์ด๋ก ์ ๋ฌ๋๊ฒ ๋๋ฉด ๋ณ๊ฒฝ๋๋ ๊ฐ์ด ์๊ธฐ ๋๋ฌธ์ ์ต์ด ๋ ๋๋ง ๋ ๋๋ง ์คํ๋๋ ๊ฒ์ด๋ค.
์ฃผ๋ก API๋ฅผ ํธ์ถํด์ ๋ฐ์ดํฐ๋ฅผ ์ป์ ๋ ์ฌ์ฉํ๋ค.
import { useEffect, useState } from 'react';
export default function TimerControl() {
const [playing, setPlaying] = useState(false);
useEffect(() => {
console.log('์ต์ด ๋ ๋๋ง์์๋ง ์คํ!');
},[]); // ๋น๋ฐฐ์ด
const handleClick = () => {
console.log('Click!');
setPlaying(!playing);
};
return (
<div>
<button type="button" onClick={handleClick}>
ํ ๊ธ ๋ฒํผ {playing ? `on` : `off`}
</button>
</div>
);
}
์์กด์ฑ ๋ฐฐ์ด ์ฌ์ฉ
import { useEffect, useState } from 'react';
export default function TimerControl() {
const [playing, setPlaying] = useState(false);
const [count, setCount] = useState(0);
useEffect(() => {
console.log('playing๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์คํ!');
}, [playing]); // playing ์ํ๊ฐ ์ธ์๋ก ์ ๋ฌ
const handleToggleClick = () => {
console.log('Toggle Click!');
setPlaying(!playing);
};
const handleAddClick = () => {
console.log('Add Click!');
setCount(count+1);
};
return (
<div>
<button type="button" onClick={handleToggleClick}>
ํ ๊ธ ๋ฒํผ {playing ? `on` : `off`}
</button>
<p>{count}</p>
<button type="button" onClick={handleAddClick}>
์ฆ๊ฐ ๋ฒํผ
</button>
</div>
);
}
์์ ์ฝ๋๋ ์์กด์ฑ๋ฐฐ์ด์ playing
state ๊ฐ์ ์ธ์๋ก ์ ๋ฌํ์๋ค. playing
์ ์ํ๊ฐ์ด ๋ณ๊ฒฝ ๋ ๋ ๋ง๋ค useEffect์ ์ฝ๋ฐฑํจ์๊ฐ ์คํ๋๋ ๊ฑธ ์ ์ ์๋ค.
์ ๋ฆฌ(clean-up)๋ฅผ ์ด์ฉํ๋ Effects
์ ๋ฆฌ(clean-up)๊ฐ ํ์ํ Side effect๋ ์๋ค. ์ธ๋ถ ๋ฐ์ดํฐ์ ๊ตฌ๋ (subscription)์ ์ค์ ํด์ผ ํ๋ ๊ฒฝ์ฐ,์ด๋ฐ ๊ฒฝ์ฐ์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ์ง ์๋๋ก ์ ๋ฆฌ(clean-up)ํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํ๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์๋์ง ์๋๋ก ๋ฑ๋กํ ์ด๋ฒคํธ๋ฅผ ์ ๊ฑฐํด์ฃผ๋ ํจ์๊ฐ ํ์ํ ๊ฒฝ์ฐ
import { useEffect, useState } from 'react';
export default function TimerControl() {
const [count, setCount] = useState(1000);
useEffect(() => {
console.log('useEffect ์คํ');
return () => {
console.log('return ๋ฌธ์ ํจ์ === cleanup');
};
}, [count]);
const countHander = (e) => {
setCount((c) => c + 1000);
};
return (
<div className="App">
<h1>{count}</h1>
<button onClick={countHander}>์นด์ดํธ ์ฆ๊ฐ</button>
</div>
);
}
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด useEffect ํจ์์ return๋ฌธ์ด ์ถ๊ฐ๋์๋ค. return๋ฌธ์ ์ฒซ ๋ ๋๋ง ์์ ์๋ return๋ฌธ์ ํจ์๋ ์คํ๋์ง ์๋๋ค. ์นด์ดํธ ์ฆ๊ฐ ๋ฒํผ์ ํด๋ฆญํ๋ฉด useEffect๊ฐ ๋ค์ ํธ์ถ๋๊ธฐ ์ ์ useEffect์ return์ ์์ฑํ ์ฝ๋ฐฑ์ด ์คํ๋๋ค.
โ useEffect์ return์ผ๋ก ๋ฐํ๋๋ ํจ์๋
์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ด ๋น๋ฐฐ์ด ๊ฒฝ์ฐ : ์ปดํฌ๋ํธ๊ฐ ์ต์ข ์ ์ผ๋ก DOM์์ unmount๋๋ ์์ ์๋ง ์ํ
์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ด ์๋ ๊ฒฝ์ฐ : ๊ฐ์ ๋ณ๊ฒฝ์ด ๊ฐ์ง๋ ๋๋ง๋ค useEffect๊ฐ ์ฌ์ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ return๋ฌธ ํจ์ ๋ํ ๊ณ์ ์คํ
โ๐ป useEffect ์ฌ์ฉ๋ฒ ์ ๋ฆฌ
useEffect(() => {
// ๋งค ๋ ๋๋ง๋ง๋ค ์คํ
});
useEffect(() => {
// ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง๋ ์คํ
}, []);
useEffect(() => {
// ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง๋ ์ดํ ์คํ
// a๋ b๊ฐ ๋ณ๊ฒฝ๋์ด ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ ๋๋ง๋ ์ดํ ์คํ
}, [a, b]);
useEffect(() => {
return () => {
// ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ผ์ง๋ ์์
}
}, []);
useEffect(() => {
// 2. return๋ฌธ์ ํจ์๊ฐ ์คํ ๋ ํ ์คํ
return () => {
// 1. a๋ b๊ฐ ๋ณ๊ฒฝ๋์ด ์
๋ฐ์ดํธ๊ฐ ๋๊ธฐ ์ ์ ๋จผ์ ์คํ
}
}, [a, b]);
Effect๊ฐ ๋ ๋ฒ ์คํ๋๋ ๋ฌธ์
<React.StrictMode>๋ก ์ปดํฌ๋ํธ ์ ์ฒด๋ฅผ ๊ฐ์ ๊ฒฝ์ฐ, ์์์น ๋ชปํ Side Effect๋ฅผ ์ฐพ์ผ๋ ค๊ณ Effect ๋ฑ์ ๋ ๋ฒ์ฉ ์คํํ๋ค.
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

๐ useLayoutEffect๋?
๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๋ค์ ์ฑ์ฐ๊ธฐ ์ ์ ์คํ๋๋ ๋ฒ์ ์ useEffect
๋ ๋๋งํ ์ํ๊ฐ effect ๋ด์์ ์ด๊ธฐํ ๋์ด์ผ ํ ๊ฒฝ์ฐ, ์ฌ์ฉ์ ๊ฒฝํ์ ์ํด ์ฌ์ฉ๋๋ค.
useEffect vs useLayoutEffect
์ด๋ฒคํธ์ ํธ์ถ(์คํ)์์ ์ ์ฐจ์ด
useEffect
์ ๊ฒฝ์ฐ DOM์ ๋ ์ด์์ ๋ฐฐ์น์ ํ์ธํธ๊ฐ ๋๋ ํ ์ดํํธ ํจ์๋ฅผ ํธ์ถํ๋ค. useEffect ๋ด๋ถ์ Dom์ ์ํฅ์ ์ฃผ๋ ์ฝ๋๊ฐ ์์ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์
์ฅ์์๋ ํ๋ฉด์ ๊น๋นก์์ ๊ฒฝํํ๊ฒ ๋๋ค. useLayoutEffect
์ ๊ฒฝ์ฐ DOM์ ๋ ์ด์์ ๋ฐฐ์น๊ฐ ๋๋ ํ ์ดํํธ ํจ์๋ฅผ ํธ์ถํ๊ณ ํ์ธํธ๋ฅผ ์คํํ๊ฒ ๋๋ค. paint๊ฐ ๋๊ธฐ์ ์ ์คํ๋๊ธฐ ๋๋ฌธ์ Dom์ ์กฐ์ํ๋ ์ฝ๋๊ฐ ์กด์ฌํ๋๋ผ๋ ์ฌ์ฉ์๋ ๊น๋นก์์ ๊ฒฝํํ์ง ์๋๋ค.
import { useEffect, useState } from "react";
function App() {
const [age, setAge] = useState(0);
const [name, setName] = useState("");
useEffect(() => { // useLayoutEffect ๋ณ๊ฒฝํด๋ณด๋ฉด ์ฐจ์ด๋ฅผ ๋๋ ์ ์๋ค.
setAge(25);
setName("์ฐฌ๋ฏผ");
}, []);
return (
<>
<div className="App">{`๊ทธ์ ์ด๋ฆ์ ${name} ์ด๋ฉฐ, ๋์ด๋ ${age}์ด ์
๋๋ค.`}</div>
</>
);
}
export default App;
๐ ์ฐธ๊ณ
Last updated