useEffect
useEffect
๋ ์ธ๋ถ ์์คํ
๊ณผ ์ปดํฌ๋ํธ๋ฅผ ๋๊ธฐํํ๋ React Hook์
๋๋ค.
useEffect(setup, dependencies?)
- ๋ ํผ๋ฐ์ค
- ์ฌ์ฉ๋ฐฉ๋ฒ
- ์ธ๋ถ ์์คํ ๊ณผ ์ฐ๊ฒฐ
- ์ปค์คํ Hook์ Effect๋ก ๊ฐ์ธ๊ธฐ
- ๋ฆฌ์กํธ๋ก ์์ฑ๋์ง ์์ ์์ ฏ ์ ์ดํ๊ธฐ
- Effect๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ํ์นญ
- ๋ฐ์ํ๊ฐ ์์กด์ฑ ์ง์
- Effect์์ ์ด์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก state ์ ๋ฐ์ดํธํ๊ธฐ
- ๋ถํ์ํ ๊ฐ์ฒด ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- ๋ถํ์ํ ํจ์ ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- Effect์์ ์ต์ props์ state๋ฅผ ์ฝ๊ธฐ
- ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ์ปจํ ์ธ ๋ฅผ ํ์ํ๊ธฐ
- ํธ๋ฌ๋ธ ์ํ
- Effect๊ฐ ์ปดํฌ๋ํธ ๋ง์ดํธ ์ 2๋ฒ ๋์ํฉ๋๋ค.
- Effect๊ฐ ๋งค ๋ฆฌ๋ ๋๋ง๋ง๋ค ์คํ๋ฉ๋๋ค.
- Effect๊ฐ ๋ฌดํ ๋ฐ๋ณต๋ฉ๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋์ง ์์์์๋ ์ ๋ฆฌ ํจ์๊ฐ ์คํ๋ฉ๋๋ค.
- Effect๊ฐ ์๊ฐ์ ์ธ ์์ ์ ์ํํ๋ฉฐ, ์คํ๋๊ธฐ ์ ์ ๊น๋นก์์ด ๋ณด์ ๋๋ค.
๋ ํผ๋ฐ์ค
useEffect(setup, dependencies?)
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useEffect
๋ฅผ ํธ์ถํ์ฌ Effect๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค.
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
์๋์์ ๋ ๋ง์ ์์ ๋ฅผ ๋ณด์ธ์.
๋งค๊ฐ๋ณ์
-
setup(์ค์ )
: Effect์ ๋ก์ง์ด ํฌํจ๋ ํจ์์ ๋๋ค. ์ค์ ํจ์๋ ์ ํ์ ์ผ๋ก clean up(์ ๋ฆฌ) ํจ์๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค. React๋ ์ปดํฌ๋ํธ๊ฐ DOM์ ์ถ๊ฐ๋ ์ดํ์ ์ค์ ํจ์๋ฅผ ์คํํฉ๋๋ค. ์์กด์ฑ์ ๋ณํ์ ๋ฐ๋ผ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง์ด ๋์์ ๊ฒฝ์ฐ, (์ค์ ํจ์์ ์ ๋ฆฌ ํจ์๋ฅผ ์ถ๊ฐํ์๋ค๋ฉด) React๋ ์ด์ ๋ ๋๋ง์ ์ฌ์ฉ๋ ๊ฐ์ผ๋ก ์ ๋ฆฌ ํจ์๋ฅผ ์คํํ ํ ์๋ก์ด ๊ฐ์ผ๋ก ์ค์ ํจ์๋ฅผ ์คํํฉ๋๋ค. ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋ ๊ฒฝ์ฐ์๋ ์ ๋ฆฌ ํจ์๋ฅผ ์คํํฉ๋๋ค. -
dependencies
์ ํ์ฌํญ :์ค์
ํจ์์ ์ฝ๋ ๋ด๋ถ์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ๋ค์ด ํฌํจ๋ ๋ฐฐ์ด๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ฐ์ํ ๊ฐ์๋ props์ state, ๋ชจ๋ ๋ณ์ ๋ฐ ์ปดํฌ๋ํธ body์ ์ง์ ์ ์ผ๋ก ์ ์ธ๋ ํจ์๋ค์ด ํฌํจ๋ฉ๋๋ค. ๋ฆฐํฐ๊ฐ ๋ฆฌ์กํธ ํ๊ฒฝ์ ๋ง๊ฒ ์ค์ ๋์ด ์์ ๊ฒฝ์ฐ, ๋ฆฐํฐ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ๋ค์ด ์์กด์ฑ์ ์ ๋๋ก ๋ช ์๋์ด ์๋์ง ๊ฒ์ฆํ ๊ฒ์ ๋๋ค. ์์กด์ฑ ๋ฐฐ์ด์ ํญ์ ์ผ์ ํ ์์ ํญ๋ชฉ์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ฉฐ[dep1, dep2, dep3]
๊ณผ ๊ฐ์ด ์์ฑ๋์ด์ผ ํฉ๋๋ค. React๋ ๊ฐ๊ฐ์ ์์กด์ฑ๋ค์Object.is
๋น๊ต๋ฒ์ ํตํด ์ด์ ๊ฐ๊ณผ ๋น๊ตํฉ๋๋ค. ์์กด์ฑ์ ์๋ตํ ๊ฒฝ์ฐ, Effect๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ๋๋ง๋ค ์คํ๋ฉ๋๋ค. ์ธ์์ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํ์ ๋, ๋น ๋ฐฐ์ด์ ์ถ๊ฐํ์ ๋, ์์กด์ฑ์ ์ถ๊ฐํ์ง ์์์ ๋์ ์ฐจ์ด๋ฅผ ํ์ธํด ๋ณด์ธ์.
๋ฐํ๊ฐ
useEffect
๋ undefined
๋ฅผ ๋ฐํํฉ๋๋ค.
์ฃผ์์ฌํญ
-
useEffect
๋ Hook์ด๋ฏ๋ก ์ปดํฌ๋ํธ์ ์ต์์ ๋๋ ์ปค์คํ Hook์์๋ง ํธ์ถํ ์ ์์ต๋๋ค. ๋ฐ๋ณต๋ฌธ์ด๋ ์กฐ๊ฑด๋ฌธ์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ์ํ ๊ฒฝ์ฐ ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ์ถ์ถํ๊ณ ํด๋น ์ปดํฌ๋ํธ๋ก state๋ฅผ ์ด๋ํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. -
์ธ๋ถ ์์คํ ๊ณผ ์ปดํฌ๋ํธ๋ฅผ ๋๊ธฐํํ ํ์๊ฐ ์๋ ๊ฒฝ์ฐ, Effect๋ฅผ ์ ์ธํ ํ์๊ฐ ์์ ์ ์์ต๋๋ค.
-
Strict Mode๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, React๋ ์ค์ ์ฒซ ๋ฒ์งธ ์ค์ ํจ์๊ฐ ์คํ๋๊ธฐ ์ด์ ์ ๊ฐ๋ฐ ๋ชจ๋์๋ง ํ์ ํ์ฌ ํ ๋ฒ์ ์ถ๊ฐ์ ์ธ ์ค์ + ์ ๋ฆฌ ์ฌ์ดํด์ ์คํํฉ๋๋ค. ์ด๋ ์ ๋ฆฌ ๋ก์ง์ด ์ค์ ๋ก์ง์ ์๋ฒฝํ โ๋ฐ์โํ๊ณ ์ค์ ๋ก์ง์ด ์ํํ๋ ์์ ์ ์ค๋จํ๊ฑฐ๋ ์ทจ์ํ ์ ์๋์ง๋ฅผ ํ์ธํ๋ ์คํธ๋ ์ค ํ ์คํธ์ ๋๋ค. ์ด์ ๋ฐ๋ผ ๋ฌธ์ ๊ฐ ์๊ธธ ๊ฒฝ์ฐ, ์ ๋ฆฌ ํจ์๋ฅผ ๊ตฌํํ์ญ์์ค.
-
๋ง์ฝ ์์กด์ฑ์ด ๊ฐ์ฒด์ด๊ฑฐ๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ ์ธ๋ ํจ์์ผ ๊ฒฝ์ฐ์๋ Effect๊ฐ ํ์ ์ด์์ผ๋ก ์ฌ์คํ๋ ์ ์์ต๋๋ค. ์ด๋ฅผ ์์ ํ๋ ค๋ฉด ๋ถํ์ํ ๊ฐ์ฒด ์์กด์ฑ์ด๋ ํจ์ ์์กด์ฑ์ ์ ๊ฑฐํ์ธ์. ๋๋ state ์ ๋ฐ์ดํธ๋ฅผ ์ถ์ถํ๊ฑฐ๋ Effect ๋ฐ์ผ๋ก ๋น ๋ฐ์ํ ๋ก์ง์ ๋นผ๋ผ ์ ์์ต๋๋ค.
-
Effect๊ฐ ์ํธ์์ฉ(ํด๋ฆญ๊ณผ ๊ฐ์)์ ์ํด ์ผ์ด๋์ง ์๋๋ค๋ฉด, React๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๋ฐ์ดํธ๋ ํ๋ฉด์ ๊ทธ๋ฆฌ๋๋ก ํ์ฉํ ํ Effect๋ฅผ ์คํํฉ๋๋ค. ๋ง์ฝ Effect๋ก ์ํํ๋ ์์ ์ด ์๊ฐ์ ์ธ ํจ๊ณผ๊ฐ ์๊ณ ์ง์ฐ์ด ๋์ ๋๊ฒ ๋ฐ์ํ๋ค๋ฉด(์๋ฅผ ๋ค์ด, ํดํ์ ์์น์ํค๋ ๊ฒฝ์ฐ์ ๊ฐ์ด ํ๋ฉด์ ์ด๋ค ๋ณํ๋ฅผ ์ฃผ๋ ๊ฒฝ์ฐ),
useEffect
๋์useLayoutEffect
๋ฅผ ์ฌ์ฉํ์ญ์์ค. -
Effect๊ฐ ์ํธ์์ฉ(ํด๋ฆญ๊ณผ ๊ฐ์)์ ์ํด ์ผ์ด๋๋ค๊ณ ํ๋๋ผ๋ ๋ธ๋ผ์ฐ์ ๋ Effect ๋ด๋ถ์ state๊ฐ ์ ๋ฐ์ดํธ๋๊ธฐ ์ด์ ์ ํ๋ฉด์ ๋ฆฌํ์ธํ ํ ๊ฒ์ ๋๋ค. ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ์๋ํ ์ํฉ์ผ ์ ์์ผ๋, ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๋ฆฌํ์ธํ ํ๋ ๊ฒ์ ๋ธ๋กํนํ๊ณ ์ถ๋ค๋ฉด
useEffect
๋์useLayoutEffect
๋ฅผ ์ฌ์ฉํ์ญ์์ค. -
Effect๋ client ํ๊ฒฝ์์๋ง ๋์ํฉ๋๋ค. ์๋ฒ ๋ ๋๋ง์์๋ ๋์ํ์ง ์์ต๋๋ค.
์ฌ์ฉ๋ฐฉ๋ฒ
์ธ๋ถ ์์คํ ๊ณผ ์ฐ๊ฒฐ
๋ช๋ช ์ปดํฌ๋ํธ๋ค์ ํ์ด์ง์ ํ์๋๋ ๋์ ๋คํธ์ํฌ๋ ๋ธ๋ผ์ฐ์ API, ๋๋ ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฐ๊ฒฐ์ด ์ ์ง๋์ด์ผ ํฉ๋๋ค. React์ ์ ์ด๋์ง ์๋ ์ด๋ฌํ ์์คํ ๋ค์ ์ธ๋ถ ์์คํ (external) ์ด๋ผ ๋ถ๋ฆ ๋๋ค.
์ปดํฌ๋ํธ๋ฅผ ์ธ๋ถ ์์คํ
๊ณผ ์ฐ๊ฒฐํ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useEffect
๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค.
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}
useEffect
๋ 2๊ฐ์ ์ธ์๊ฐ ํ์ํฉ๋๋ค.
- ์ธ๋ถ ์์คํ
๊ณผ ์ปดํฌ๋ํธ๋ฅผ ์ฐ๊ฒฐํ๋ ์ค์ ์ฝ๋๊ฐ ํฌํจ๋ ์ค์ ํจ์
- ์ธ๋ถ ์์คํ ๊ณผ์ ์ฐ๊ฒฐ์ ํด์ ํ๋ ์ ๋ฆฌ ์ฝ๋๊ฐ ํฌํจ๋ ์ ๋ฆฌ ํจ์๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
- ์ ํจ์ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์์ ๋น๋กฏ๋ ๋ฐ์ํ ๊ฐ๋ค์ ํฌํจํ๋ ์์กด์ฑ ๋ฐฐ์ด
React๋ ์ค์ ํจ์์ ์ ๋ฆฌ ํจ์๊ฐ ํ์ํ ๋๋ง๋ค ํธ์ถํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ฌ๋ฌ ๋ฒ ํธ์ถ๋ ์ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์ถ๊ฐ๋์์ ๋ ์ค์ ์ฝ๋๊ฐ ๋์ํฉ๋๋ค (๋ง์ดํธ ์).
- ์์กด์ฑ์ด ๋ณ๊ฒฝ๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋ ๋๋ง๋ค ์๋ ๋์์ ์ํํฉ๋๋ค.
- ๋จผ์ ์ ๋ฆฌ ์ฝ๋๊ฐ ์ค๋๋ props์ state์ ํจ๊ป ์คํ๋ฉ๋๋ค.
- ์ดํ, ์ค์ ์ฝ๋๊ฐ ์๋ก์ด props์ state์ ํจ๊ป ์คํ๋ฉ๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์์ ์ ๊ฑฐ๋ ์ดํ์ ์ ๋ฆฌ ์ฝ๋๊ฐ ๋ง์ง๋ง์ผ๋ก ์คํ๋ฉ๋๋ค (๋ง์ดํธ ํด์ ์).
์์ ์์ ๋ฅผ ํตํด ์์๋ฅผ ์ค๋ช ํด ๋ณด๊ฒ ์ต๋๋ค.
์์ ChatRoom
์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์ถ๊ฐ๋๋ฉด ์ด๊ธฐ serverUrl
๊ณผ roomId
๋ฅผ ์ด์ฉํด ์ฑํ
๋ฐฉ๊ณผ ์ฐ๊ฒฐ๋ ๊ฒ์
๋๋ค. ๋ฆฌ๋ ๋๋ง์ ์ํด serverUrl
๋๋ roomId
๊ฐ ๋ณ๊ฒฝ๋๋ค๋ฉด (์๋ฅผ ๋ค์ด ์ฌ์ฉ์๊ฐ ๋๋กญ๋ค์ด ๋ฉ๋ด๋ฅผ ์ด์ฉํด ๋ค๋ฅธ ์ฑํ
๋ฐฉ์ ์ ํํ ๊ฒฝ์ฐ) Effect๋ ์ด์ ์ฑํ
๋ฐฉ๊ณผ์ ์ฐ๊ฒฐ์ ํด์ ํ๊ณ ๋ค์ ์ฑํ
๋ฐฉ๊ณผ ์ฐ๊ฒฐํฉ๋๋ค. ChatRoom
์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์์ ์ ๊ฑฐ๋๋ค๋ฉด Effect๋ ๋ง์ง๋ง ์ฑํ
๋ฐฉ๊ณผ ์ด๋ค์ง ์ฐ๊ฒฐ์ ํด์ ํ ๊ฒ์
๋๋ค.
๋ฆฌ์กํธ๋ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ชจ๋์์ ์ค์ ์ด ์คํ๋๊ธฐ ์ ์ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ํ ๋ฒ ๋ ์คํ์ํต๋๋ค. ์ด๋ ์คํธ๋ ์ค ํ ์คํธ์ ํ๋๋ก์จ Effect์ ๋ก์ง์ด ์ ํํ๊ฒ ์ํ๋๊ณ ์๋์ง๋ฅผ ๊ฒ์ฆํฉ๋๋ค. ๋ง์ฝ ๊ฐ์์ ์ธ ์ด์๊ฐ ๋ณด์ธ๋ค๋ฉด ์ ๋ฆฌ ํจ์์ ๋ก์ง์ ๋์น ๋ถ๋ถ์ด ์๋ ๊ฒ์ ๋๋ค. ์ ๋ฆฌ ํจ์๋ ์ค์ ํจ์์ ์ด๋ ํ ๋์์ด๋ผ๋ ์ค์งํ๊ฑฐ๋ ์คํ ์ทจ์๋ฅผ ํ ์ ์์ด์ผ ํ๋ฉฐ, ์ฌ์ฉ์๋ ์ค์ ํจ์๊ฐ ํ ๋ฒ ํธ์ถ๋ ๋์ ์ค์ โ ์ ๋ฆฌ โ ์ค์ ์์๋ก ํธ์ถ๋ ๋์ ์ฐจ์ด๋ฅผ ๋๋ ์ ์์ด์ผ ํฉ๋๋ค.
๊ฐ๊ฐ์ Effect๋ฅผ ๋ ๋ฆฝ์ ์ธ ํ๋ก์ธ์ค๋ก ์์ฑํ๊ณ ์ ํํ ์ค์ /์ ๋ฆฌ ์ฌ์ดํด์ ๊ณ ๋ คํ์ธ์. ์ปดํฌ๋ํธ์ ๋ง์ดํธ, ์ ๋ฐ์ดํธ, ๋ง์ดํธ ํด์ ์ฌ๋ถ๋ ์ค์ํ์ง ์์์ผ ํฉ๋๋ค. ์ ๋ฆฌ ๋ก์ง์ด ์ค์ ๋ก์ง๊ณผ ์ ํํ๊ฒ โ๋ฏธ๋ฌ๋งโ๋ ๋, Effect๋ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ํ์ํ ๋งํผ ๊ฒฌ๊ณ ํ๊ฒ ์ฒ๋ฆฌํฉ๋๋ค.
์์ 1 of 5: ์ฑํ
์๋ฒ์ ์ฐ๊ฒฐ
์ด ์์์์๋ ChatRoom
์ปดํฌ๋ํธ์ Effect๋ฅผ ํตํด chat.js
๋ก ์ ์๋ ์ธ๋ถ ์์คํ
๊ณผ ์ฐ๊ฒฐ์ ์ ์งํฉ๋๋ค. โOpen chatโ์ ๋๋ฅด๋ฉด ChatRoom
์ปดํฌ๋ํธ๊ฐ ๋ํ๋ฉ๋๋ค. ์ด ์๋๋ฐ์ค๋ ๊ฐ๋ฐ ๋ชจ๋์์ ๋์ํ๋ฏ๋ก ์ถ๊ฐ์ ์ธ ์ฐ๊ฒฐ-์ฐ๊ฒฐํด์ ์ฌ์ดํด์ด ๋์ํฉ๋๋ค. ๋๋กญ๋ค์ด ๋ฉ๋ด๋ input์ ์ด์ฉํด roomId
๋๋ serverUrl
๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ด๋ป๊ฒ Effect๊ฐ chat์ ์ฌ์ฐ๊ฒฐํ๋์ง ํ์ธํด ๋ณด์ธ์. โClose chatโ์ ๋๋ฌ Effect๊ฐ ๋ง์ง๋ง์ ์ฐ๊ฒฐ๋์๋ chat์ ์ฐ๊ฒฐ ํด์ ํ๋ ๊ฒ๋ ํ์ธํด ๋ณด์ธ์.
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); const [show, setShow] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> {show && <hr />} {show && <ChatRoom roomId={roomId} />} </> ); }
์ปค์คํ Hook์ Effect๋ก ๊ฐ์ธ๊ธฐ
Effect๋ โํ์ถ๊ตฌโ ์ ๋๋ค. โReact ๋ฐ๊นฅ์ผ๋ก ๋๊ฐ์ผ ํ ๋โ์ ์ ์ฆ์ผ์ด์ค์ ํ์ํ ๋นํธ์ธ ์๋ฃจ์ ์ด ์์ ๋ ์ฌ์ฉํฉ๋๋ค. ๋ง์ฝ Effect๋ฅผ ์์ฃผ ์์ฑํด์ผ ํ๋ค๋ฉด ์ปดํฌ๋ํธ๊ฐ ์์กดํ๊ณ ์๋ ๊ณตํต์ ์ธ ๋์๋ค์ ์ปค์คํ Hook์ผ๋ก ์ถ์ถํด์ผ ํ๋ค๋ ์ ํธ์ผ ์ ์์ต๋๋ค.
์์๋ก ์๋์ useChatRoom
์ปค์คํ
Hook์ Effect์ ๋ก์ง์ ์กฐ๊ธ ๋ ์ ์ธ์ ์ธ API๋ก ๋ณด์ผ ์ ์๋๋ก ์จ๊ฒจ์ค๋๋ค.
function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId, serverUrl]);
}
์ด์ ์ด ์ปค์คํ Hook์ ์ด๋ค ์ปดํฌ๋ํธ์์๋ ์ด์ฉํ ์ ์์ต๋๋ค.
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useChatRoom({
roomId: roomId,
serverUrl: serverUrl
});
// ...
๋ํ React ์ํ๊ณ์๋ ๊ฐ์ข ๋ชฉ์ ์ ๋ง๋ ํ๋ฅญํ ์ปค์คํ Hook๋ค๋ ๋ง์ด ์กด์ฌํฉ๋๋ค.
์ด ๋งํฌ๋ฅผ ํตํด ์ปค์คํ Hook์ ๋ํด ๋ ๋ง์ด ๊ณต๋ถํด๋ณด์ธ์.
์์ 1 of 3: ์ปค์คํ
useChatRoom
Hook
์ด ์์ ๋ ์ด์ ์์ ์ค ํ๋์ ๋์ผํ์ง๋ง ๋ก์ง์ด ์ปค์คํ Hook์ผ๋ก ์ถ์ถ๋์์ต๋๋ค.
import { useState } from 'react'; import { useChatRoom } from './useChatRoom.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); const [show, setShow] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> {show && <hr />} {show && <ChatRoom roomId={roomId} />} </> ); }
๋ฆฌ์กํธ๋ก ์์ฑ๋์ง ์์ ์์ ฏ ์ ์ดํ๊ธฐ
๊ฐ๋์ ์ปดํฌ๋ํธ์ prop ๋๋ state๋ฅผ ์ธ๋ถ ์์คํ ๊ณผ ๋๊ธฐํํด์ผํ ๋๊ฐ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด React ์์ด ์์ฑ๋ third-party ์ง๋ ์์ ฏ์ด๋ ๋น๋์ค ํ๋ ์ด์ด ์ปดํฌ๋ํธ๊ฐ ์๋ค๋ฉด ์ด ์ปดํฌ๋ํธ์ state๋ฅผ ํ์ฌ React ์ปดํฌ๋ํธ์ state์ ์ผ์นํ๋๋ก ํ๊ธฐ ์ํด Effect๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด Effect๋ map-widget.js
์ ์ ์๋ MapWidget
ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค. Map
์ปดํฌ๋ํธ์ zoomLevel
prop์ ๋ณ๊ฒฝํ ๋, Effect๋ ํด๋น ํด๋์ค ์ธ์คํด์ค์ setZoom()
์ ํธ์ถํ์ฌ ๋๊ธฐํ๋ฅผ ์ ์งํฉ๋๋ค.
import { useRef, useEffect } from 'react'; import { MapWidget } from './map-widget.js'; export default function Map({ zoomLevel }) { const containerRef = useRef(null); const mapRef = useRef(null); useEffect(() => { if (mapRef.current === null) { mapRef.current = new MapWidget(containerRef.current); } const map = mapRef.current; map.setZoom(zoomLevel); }, [zoomLevel]); return ( <div style={{ width: 200, height: 200 }} ref={containerRef} /> ); }
์ด ์์ ์์๋ ์ ๋ฆฌ ํจ์๊ฐ ํ์ํ์ง ์์ต๋๋ค. ์ด๋ MapWidget
ํด๋์ค๊ฐ ํด๋์ค์ ์ ๋ฌ๋ DOM ๋
ธ๋๋ง ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์
๋๋ค. Map
์ปดํฌ๋ํธ๊ฐ ํธ๋ฆฌ์์ ์ ๊ฑฐ๋ ํ, ๋ธ๋ผ์ฐ์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ํด DOM ๋
ธ๋์ MapWidget
ํด๋์ค ์ธ์คํด์ค ๋ชจ๋๊ฐ ์๋์ผ๋ก ๊ฐ๋น์ง ์ปฌ๋ ์
์ ์ํด ์ ๋ฆฌ๋ฉ๋๋ค.
Effect๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ํ์นญ
์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ธฐ ์ํด Effect๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ง์ฝ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ํ๋ ์์ํฌ์ ๋ฐ์ดํฐ ํ์นญ ๋ฉ์ปค๋์ฆ์ ์ด์ฉํ๋ ๊ฒ์ด Effect๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒ๋ณด๋ค ๋ ํจ์จ์ ์ผ ๊ฒ์ ๋๋ค.
๋ง์ฝ ์ง์ Effect๋ฅผ ์์ฑํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ณ ์ถ๋ค๋ฉด, ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค.
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]);
// ...
ignore
๋ณ์์ ์ด๊ธฐ๊ฐ์ด false
๋ก ์ค์ ๋๊ณ ์ ๋ฆฌ ํจ์ ๋์ ์ค์ true
๋ก ์ค์ ๋๋ ๊ฒ์ ์ฃผ๋ชฉํ์ธ์. ์ด ๋ก์ง์ ์ฝ๋๊ฐ โ๊ฒฝ์ ์ํ(race conditions)โ์ ๋น ์ง์ง ์๋๋ก ๋ณด์ฅํด ์ค๋๋ค. ๋คํธ์ํฌ ์์ฒญ์ ๋ณด๋ธ ์์์ ์๋ต์ ๋ฐ๋ ์์๊ฐ ๋ค๋ฅด๊ฒ ๋์ํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
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> </> ); }
๋ํ async
/ await
๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ๋ค์ ์์ฑํ ์ ์์ง๋ง ์ฌ์ ํ ์ ๋ฆฌ ํจ์๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
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(() => { async function startFetching() { setBio(null); const result = await fetchBio(person); if (!ignore) { setBio(result); } } let ignore = false; startFetching(); 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> </> ); }
Effect์์ ์ง์ ๋ฐ์ดํฐ ํ์นญ ๋ก์ง์ ์์ฑํ๋ฉด ๋์ค์ ์บ์ฑ ๊ธฐ๋ฅ์ด๋ ์๋ฒ ๋ ๋๋ง๊ณผ ๊ฐ์ ์ต์ ํ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ด๋ ค์์ง๋๋ค. ์์ฒด ์ ์๋ ์ปค์คํ Hook์ด๋ ์ปค๋ฎค๋ํฐ์ ์ํด ์ ์ง๋ณด์๋๋ Hook์ ์ฌ์ฉํ๋ ํธ์ด ๋ ๊ฐ๋จํฉ๋๋ค.
Deep Dive
Effect ๋ด๋ถ์์ fetch
ํธ์ถ์ ์์ฑํ๋ ๊ฒ์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์ฑ์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ๋ฐฉ๋ฒ์
๋๋ค. ํ์ง๋ง ์ด๊ฒ์ ๋งค์ฐ ์๋์ ์ธ ์ ๊ทผ ๋ฐฉ์์ด๋ฉฐ ํฐ ๋จ์ ์ด ์์ต๋๋ค.
- Effect๋ ์๋ฒ์์๋ ์คํ๋์ง ์์ต๋๋ค. ์ด๋ ์ด๊ธฐ ์๋ฒ ๋ ๋๋ง ๋ HTML์ด ๋ฐ์ดํฐ๊ฐ ์๋ state๋ง์ ํฌํจํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ํด๋ผ์ด์ธํธ ์ปดํจํฐ๋ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ด๋ก๋ ๋ฐ๊ณ ์ฑ์ ๋ ๋๋งํ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค. ์ด๋ ํจ์จ์ ์ด์ง ์์ ์ ์์ต๋๋ค.
- Effect ๋ด๋ถ์์ ์ง์ ํ์นญ์ ํ๋ ๊ฒ์ ๋คํธ์ํฌ ํญํฌ(network waterfalls)๊ฐ ์์ฑ๋๊ธฐ ์ฝ๊ฒ ํฉ๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ ๋ ๋๋ง ํ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ณ ๋์ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ฉ๋๋ค. ์ดํ ์์ ์ปดํฌ๋ํธ๊ฐ ์์ ์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ธฐ ์์ํฉ๋๋ค. ๋คํธ์ํฌ์ ์๋๊ฐ ๋น ๋ฅด์ง ์๋ค๋ฉด ์ด ๋ฐฉ๋ฒ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ํ์นญํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋๋ฆฝ๋๋ค.
- Effect ๋ด๋ถ์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฒ์ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ก๋ํ๊ฑฐ๋ ์บ์ฑํ์ง ์๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๊ณ ๋ค์ ๋ง์ดํธ๋์์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์์ผ ํฉ๋๋ค.
- ์ฌ์ฉํ๊ธฐ ๋งค์ฐ ๋ถํธํ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ฒฝ์ ์กฐ๊ฑด๊ณผ ๊ฐ์ ๋ฒ๊ทธ๋ฅผ ๋ฐ์์ํค์ง ์๋๋ก fetch ํธ์ถ์ ์์ฑํ ๋ ์๋นํ ์์ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค.
์ด๋ฌํ ๋จ์ ์ ๋ฆฌ์กํธ๋ง ํด๋น๋๋ ๊ฒ์ด ์๋๋๋ค. ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ ๋๋ ํด๋น๋ฉ๋๋ค. ๋ผ์ฐํ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ์ดํฐ ํ์นญ์ ์ธ๋ถ์ ์ธ ์ฌํญ์ด ๋ง์ผ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ ์ ๊ทผ ๋ฐฉ์์ ๊ถ์ฅํฉ๋๋ค.
- ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ํด๋น ํ๋ ์์ํฌ์ ๋ด์ฅ๋ ๋ฐ์ดํฐ ํ์นญ ๋ฉ์ปค๋์ฆ์ ํ์ฉํ์ธ์. ํ๋ ๋ฆฌ์กํธ ํ๋ ์์ํฌ๋ ๋งค์ฐ ํจ์จ์ ์ด๋ฉฐ ์์์ ์ธ๊ธํ ๋ฌธ์ ์ ์ด ์๋ ํตํฉ๋ ๋ฐ์ดํฐ ํ์นญ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, ํด๋ผ์ด์ธํธ ์ธก ์บ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ง์ ๊ฐ๋ฐ์ ๊ณ ๋ คํด ๋ณด์ธ์. ์ธ๊ธฐ ์๋ ์คํ์์ค ์๋ฃจ์ ์ผ๋ก๋ React Query, useSWR, ๊ทธ๋ฆฌ๊ณ React Router 6.4+.๊ฐ ์์ต๋๋ค. ๋ฌผ๋ก ์ง์ ์๋ฃจ์ ์ ๊ฐ๋ฐํ ์๋ ์์ผ๋ฉฐ ์ด ๊ฒฝ์ฐ์๋ ์ดํํธ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ฉด์๋ ๋ฐ์ดํฐ ์ฌ์ ๋ก๋ ๋๋ ๋ฐ์ดํฐ ์๊ตฌ์ฌํญ์ ๋ผ์ฐํธ๋ก ํธ์ด์คํ ํ๋ ๋ฐฉ๋ฒ์ ํตํด ์ค๋ณต ์์ฒญ ๋ฐฉ์ง, ์๋ต ์บ์ฑ ๋ฐ ๋คํธ์ํฌ ํญํฌ ํจ๊ณผ ๋ฐฉ์ง๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.
๋ง์ฝ ์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ด ์ ํฉํ์ง ์๋ค๋ฉด Effect ๋ด๋ถ์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฒ์ ๊ณ์ ์งํํ ์ ์์ต๋๋ค.
๋ฐ์ํ๊ฐ ์์กด์ฑ ์ง์
Effect์ ์์กด์ฑ์ โ์ ํโํ ์ ์๋ค๋ ์ ์ ์ ์ํ์ธ์. Effect ์ฝ๋์์ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ์์กด์ฑ์ผ๋ก ์ ์ธ๋์ด์ผ ํฉ๋๋ค. Effect์ ์์กด์ฑ ๋ฐฐ์ด์ ์ฝ๋์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค.
function ChatRoom({ roomId }) { // This is a reactive value
const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // This is a reactive value too
useEffect(() => {
const connection = createConnection(serverUrl, roomId); // This Effect reads these reactive values
connection.connect();
return () => connection.disconnect();
}, [serverUrl, roomId]); // โ
So you must specify them as dependencies of your Effect
// ...
}
serverUrl
๋๋ roomId
๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค Effect๋ ์๋ก์ด ๊ฐ์ ์ด์ฉํด ์ฑํ
์ ๋ค์ ์ฐ๊ฒฐํ ๊ฒ์
๋๋ค.
๋ฐ์ํ ๊ฐ ์๋ props์ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ ์ธ๋ ๋ชจ๋ ๋ณ์๋ ํจ์๋ค์ด ํฌํจ๋ฉ๋๋ค. roomId
์ serverUrl
์ ๋ฐ์ํ ๊ฐ์ด๋ฏ๋ก ์ด๋ค์ ์์กด์ฑ์์ ์ ๊ฑฐํ๋ฉด ์ ๋ฉ๋๋ค. ์ด๋ค์ ๋๋ฝํ์ ๋ ๋ฆฐํฐ๊ฐ ๋ฆฌ์กํธ ํ๊ฒฝ์ ๋ง๊ฒ ์ค์ ๋์ด ์์๋ค๋ฉด ๋ฆฐํฐ๋ ์ด๊ฒ์ ์์ ํด์ผ ํ๋ ์ค์๋ก ํ์ํฉ๋๋ค.
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // ๐ด React Hook useEffect has missing dependencies: 'roomId' and 'serverUrl'
// ...
}
์์กด์ฑ์ ์ ๊ฑฐํ๋ ค๋ฉด ๊ทธ๊ฒ์ด ์์กด์ฑ์ด ๋์ง ์์์ผ ํจ์ ๋ฆฐํฐ์ ์ฆ๋ช
ํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, serverUrl
์ ์ปดํฌ๋ํธ ๋ฐ์ผ๋ก ์ด๋ํ์ฌ ๊ทธ๊ฒ์ด ๋ฐ์์ ์ด์ง ์๊ณ ๋ฆฌ๋ ๋๋ง๋ ๋ ๋ณ๊ฒฝ๋์ง ์์ ๊ฒ์์ ์ฆ๋ช
ํ ์ ์์ต๋๋ค.
const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // โ
All dependencies declared
// ...
}
์ด์ serverUrl
์ ๋ฐ์ํ ๊ฐ์ด ์๋๋ฉฐ (๋ฆฌ๋ ๋๋ง๋ ๋ ๋ณ๊ฒฝ๋์ง ์์ ๊ฒ์ด๋ฏ๋ก), ์์กด์ฑ์ ์ถ๊ฐํ ํ์๊ฐ ์์ต๋๋ค. Effect์ ์ฝ๋๊ฐ ์ด๋ค ๋ฐ์ํ ๊ฐ๋ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ๊ทธ ์์กด์ฑ ๋ชฉ๋ก์ ๋น์ด์์ด์ผ ํฉ๋๋ค. ([]
)
const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore
const roomId = 'music'; // Not a reactive value anymore
function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // โ
All dependencies declared
// ...
}
์์กด์ฑ์ด ๋น์ด์๋ Effect๋ ์ปดํฌ๋ํธ์ props๋ state๊ฐ ๋ณ๊ฒฝ๋๋ ๋ค์ ์คํ๋์ง ์์ต๋๋ค.
์์ 1 of 3: ์์กด์ฑ ๋ฐฐ์ด ์ ๋ฌ
์์กด์ฑ์ ๋ช ์ํ๋ฉด Effect๋ ์ด๊ธฐ ๋ ๋๋ง ํ ๊ทธ๋ฆฌ๊ณ ์์กด์ฑ ๊ฐ ๋ณ๊ฒฝ๊ณผ ํจ๊ป ๋ฆฌ๋ ๋๋ง์ด ๋ ํ ๋์ํฉ๋๋ค.
useEffect(() => {
// ...
}, [a, b]); // Runs again if a or b are different
์๋ ์์ ์์๋ serverUrl
์ roomId
์ ๋ฐ์ํ ๊ฐ์ด๋ฏ๋ก ๋ ๋ค ์์กด์ฑ์ผ๋ก ์ง์ ํด์ผ ํฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋๋กญ๋ค์ด์์ ๋ค๋ฅธ ๋ฐฉ์ ์ ํํ๊ฑฐ๋ ์๋ฒ URL ์
๋ ฅ์ ํธ์งํ๋ฉด ์ฑํ
์ด ๋ค์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ message
๋ Effect์์ ์ฌ์ฉ๋์ง ์์ผ๋ฏ๋ก(์์กด์ฑ์ด ์๋๋ฏ๋ก), ๋ฉ์ธ์ง๋ฅผ ํธ์งํด๋ ๋ํ๊ฐ ๋ค์ ์ฐ๊ฒฐ๋์ง ์์ต๋๋ค.
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [serverUrl, roomId]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> <label> Your message:{' '} <input value={message} onChange={e => setMessage(e.target.value)} /> </label> </> ); } export default function App() { const [show, setShow] = useState(false); const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> </label> {show && <hr />} {show && <ChatRoom roomId={roomId}/>} </> ); }
Effect์์ ์ด์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก state ์ ๋ฐ์ดํธํ๊ธฐ
Effect์์ ์ด์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก state๋ฅผ ์ ๋ฐ์ดํธํ๋ ค๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(count + 1); // You want to increment the counter every second...
}, 1000)
return () => clearInterval(intervalId);
}, [count]); // ๐ฉ ... but specifying `count` as a dependency always resets the interval.
// ...
}
count
๊ฐ ๋ฐ์ํ ๊ฐ์ด๋ฏ๋ก ๋ฐ๋์ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ count
๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒ์ Effect๊ฐ ์ ๋ฆฌ๋ ํ ๋ค์ ์ค์ ๋๋ ๊ฒ์ ์ผ๊ธฐํ๋ฏ๋ก count
๋ ๊ณ์ ์ฆ๊ฐํ ๊ฒ์
๋๋ค. ์ด์์ ์ด์ง ์์ ๋ฐฉ์์
๋๋ค.
์ด๋ฌํ ํ์์ ๋ฐฉ์งํ๋ ค๋ฉด c => c + 1
state ๋ณ๊ฒฝํจ์๋ฅผ setCount
์ ์ถ๊ฐํ์ธ์,
import { useState, useEffect } from 'react'; export default function Counter() { const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(c => c + 1); // โ Pass a state updater }, 1000); return () => clearInterval(intervalId); }, []); // โ Now count is not a dependency return <h1>{count}</h1>; }
c => c + 1
์ count + 1
๋์ ์ ๋ฌํ๊ณ ์์ผ๋ฏ๋ก, Effect๋ ๋ ์ด์ count
์ ์์กดํ์ง ์์ต๋๋ค. ์ด ์์ ์ผ๋ก ์ธํด count
๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค Effect๊ฐ ์ ๋ฆฌ ๋ฐ ์ค์ ์ ๋ค์ ์คํํ ํ์๊ฐ ์๊ฒ ๋ฉ๋๋ค.
๋ถํ์ํ ๊ฐ์ฒด ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
Effect๊ฐ ๋ ๋๋ง ์ค์ ์์ฑ๋ ๊ฐ์ฒด๋ ํจ์์ ์์กดํ๋ ๊ฒฝ์ฐ, ๋๋ฌด ์์ฃผ ์คํ๋ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ด Effect๋ ๋งค ๋ ๋๋ง ํ์ ๋ค์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ์ด๋ ๋ ๋๋ง๋ง๋ค options
๊ฐ์ฒด๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์
๋๋ค.
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
const options = { // ๐ฉ This object is created from scratch on every re-render
serverUrl: serverUrl,
roomId: roomId
};
useEffect(() => {
const connection = createConnection(options); // It's used inside the Effect
connection.connect();
return () => connection.disconnect();
}, [options]); // ๐ฉ As a result, these dependencies are always different on a re-render
// ...
๋ ๋๋ง ์ค์ ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ์์กด์ฑ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ํผํ์ธ์. ๋์ ๊ฐ์ฒด๋ฅผ Effect ๋ด์์ ์์ฑํ์ธ์.
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const options = { serverUrl: serverUrl, roomId: roomId }; const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
์ด์ options
๊ฐ์ฒด๋ฅผ Effect ๋ด์์ ์์ฑํ๋ฉด, Effect ์์ฒด๋ roomId ๋ฌธ์์ด์๋ง ์์กดํฉ๋๋ค.
์ด ์์ ์ผ๋ก ์
๋ ฅ๋์ ํ
์คํธ๋ฅผ ์
๋ ฅํ๋๋ผ๋ ์ฑํ
์ด ๋ค์ ์ฐ๊ฒฐ๋์ง ์์ต๋๋ค. ๊ฐ์ฒด์๋ ๋ฌ๋ฆฌ roomId
์ ๊ฐ์ ๋ฌธ์์ด์ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ค์ ํ์ง ์๋ ํ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค. ์์กด์ฑ ์ ๊ฑฐ์ ๊ดํ ์์ธํ ์ ์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ถํ์ํ ํจ์ ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
Effect๊ฐ ๋ ๋๋ง ์ค์ ์์ฑ๋ ๊ฐ์ฒด๋ ํจ์์ ์์กดํ๋ ๊ฒฝ์ฐ, ๋๋ฌด ์์ฃผ ์คํ๋ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ด Effect๋ ๋งค ๋ ๋๋ง ํ์ ๋ค์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ์ด๋ ๋ ๋๋ง๋ง๋ค createOptions
ํจ์๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์
๋๋ค.
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
function createOptions() { // ๐ฉ This function is created from scratch on every re-render
return {
serverUrl: serverUrl,
roomId: roomId
};
}
useEffect(() => {
const options = createOptions(); // It's used inside the Effect
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // ๐ฉ As a result, these dependencies are always different on a re-render
// ...
๋ฆฌ๋ ๋๋ง๋ง๋ค ํจ์๋ฅผ ์ฒ์๋ถํฐ ์์ฑํ๋ ๊ฒ ๊ทธ ์์ฒด๋ก๋ ๋ฌธ์ ๊ฐ ๋์ง ์๊ณ , ์ด๋ฅผ ์ต์ ํํ ํ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ Effect์ ์์กด์ฑ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ Effect๊ฐ ๋ฆฌ๋ ๋๋ง ํ๋ง๋ค ๋ค์ ์คํ๋๊ฒ ํฉ๋๋ค.
๋ ๋๋ง ์ค์ ์์ฑ๋ ํจ์๋ฅผ ์์กด์ฑ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ํผํ์ธ์. ๋์ Effect ๋ด์์ ํจ์๋ฅผ ์ ์ธํ์ธ์.
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { function createOptions() { return { serverUrl: serverUrl, roomId: roomId }; } const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
createOptions
ํจ์๊ฐ Effect ๋ด๋ถ์ ์ ์ธ๋์์ผ๋ฏ๋ก, Effect ์์ฒด๋ roomId
๋ฌธ์์ด์๋ง ์์กดํฉ๋๋ค. ์ด ์์ ์ ํตํด ์
๋ ฅ๋์ ์
๋ ฅํ๋ ๊ฒ๋ง์ผ๋ก ์ฑํ
์ด ๋ค์ ์ฐ๊ฒฐ๋์ง ์์ต๋๋ค. roomId
์ ๊ฐ์ ๋ฌธ์์ด์ ๋ค๋ฅธ ๊ฐ์ผ๋ก ์ค์ ํ์ง ์๋ ํ ๋ณ๊ฒฝ๋์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์์กด์ฑ ์ ๊ฑฐ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
Effect์์ ์ต์ props์ state๋ฅผ ์ฝ๊ธฐ
๊ธฐ๋ณธ์ ์ผ๋ก Effect์์ ๋ฐ์ํ ๊ฐ์ ์ฝ์ ๋๋ ํด๋น ๊ฐ์ ์์กด์ฑ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด Effect๊ฐ ํด๋น ๊ฐ์ ๋ชจ๋ ๋ณ๊ฒฝ์ โ๋ฐ์โํ๊ฒ ๋ฉ๋๋ค. ๋๋ถ๋ถ์ ์์กด์ฑ์์ ์ํ๋ ๋์์ ๋๋ค.
๊ทธ๋ฌ๋ ๋๋ก๋ Effect์์ ์ต์ props์ state๋ฅผ โ๋ฐ์โํ์ง ์๊ณ ์ฝ๊ณ ์ถ์ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํ์ด์ง ๋ฐฉ๋ฌธ๋ง๋ค ์ผํ ์นดํธ์ ๋ด๊ธด ํญ๋ชฉ ์๋ฅผ ๊ธฐ๋กํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
function Page({ url, shoppingCart }) {
useEffect(() => {
logVisit(url, shoppingCart.length);
}, [url, shoppingCart]); // โ
All dependencies declared
// ...
}
url
๋ณ๊ฒฝ๋ง๋ค ์๋ก์ด ํ์ด์ง ๋ฐฉ๋ฌธ์ ๊ธฐ๋กํ๊ณ ์ถ์ง๋ง shoppingCart
๋ง ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ์๋ ๊ธฐ๋กํ๊ณ ์ถ์ง ์๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? shoppingCart
๋ฅผ ์์กด์ฑ์์ ์ ์ธํ๋ฉด ๋ฐ์์ฑ ๊ท์น์ ์ด๊ธฐ๊ฒ ๋ฉ๋๋ค. Effect ๋ด์์ ํธ์ถ๋๋ ์ฝ๋์ด์ง๋ง ๋ณ๊ฒฝ์ ๋ฐ์ํ์ง ์๊ธฐ๋ฅผ ์ํ๋ค๋ฉด useEffectEvent
Hook์ ์ฌ์ฉํ์ฌ Effect Event
๋ฅผ ์ ์ธํ๊ณ shoppingCart
๋ฅผ ์ฝ๋ ์ฝ๋๋ฅผ ๊ทธ ์์ ์ด๋์ํฌ ์ ์์ต๋๋ค.
function Page({ url, shoppingCart }) {
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, shoppingCart.length)
});
useEffect(() => {
onVisit(url);
}, [url]); // โ
All dependencies declared
// ...
}
Effect Event๋ ๋ฐ์์ ์ด์ง ์์ผ๋ฉฐ Effect์ ์์กด์ฑ์์ ๋ฐฐ์ ๋์ด์ผ ํฉ๋๋ค. Effect Event์๋ ๋น ๋ฐ์ํ ์ฝ๋(Effect Event ๋ก์ง์ ์ต์ props์ state๋ฅผ ์ฝ์ ์ ์์)๋ฅผ ๋ฐฐ์นํ ์ ์์ต๋๋ค. onVisit
๋ด์ shoppingCart
๋ฅผ ์ฝ์์ผ๋ก์จ shoppingCart
์ ๋ณ๊ฒฝ์ผ๋ก ์ธํ Effect์ ์ฌ์คํ์ ๋ฐฉ์งํฉ๋๋ค.
์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ์ปจํ ์ธ ๋ฅผ ํ์ํ๊ธฐ
์ฑ์ด ์๋ฒ ๋ ๋๋ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ (์ง์ ๋๋ ํ๋ ์์ํฌ๋ฅผ ํตํด) ์ปดํฌ๋ํธ๋ ๋ ๊ฐ์ง ๋ค๋ฅธ ํ๊ฒฝ์์ ๋ ๋๋ง๋ฉ๋๋ค. ์๋ฒ์์๋ ์ด๊ธฐ HTML์ ์์ฑํ๊ธฐ ์ํด ๋ ๋๋ง๋๊ณ , ํด๋ผ์ด์ธํธ์์๋ React๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํด๋น HTML์ ์ฐ๊ฒฐํ๊ธฐ ์ํด ๋ค์ ๋ ๋๋ง ์ฝ๋๋ฅผ ์คํํฉ๋๋ค. ์ด๊ฒ์ด hydration์ด ์๋ํ๋ ค๋ฉด ์ด๊ธฐ ๋ ๋๋ง ์ถ๋ ฅ์ด ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋์ผํด์ผ ํ๋ ์ด์ ์ ๋๋ค.
๋๋ฌผ๊ฒ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ๋ด์ฉ์ ํ์ํด์ผ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ฑ์ด localStorage
์์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๊ฒฝ์ฐ, ์ด๋ฅผ ์๋ฒ์์ ๊ตฌํํ ์ ์์ต๋๋ค. ๋ค์์ ์ด๊ฒ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
function MyComponent() {
const [didMount, setDidMount] = useState(false);
useEffect(() => {
setDidMount(true);
}, []);
if (didMount) {
// ... return client-only JSX ...
} else {
// ... return initial JSX ...
}
}
์ฑ์ด ๋ก๋ฉ ์ค์ธ ๋์ ์ฌ์ฉ์๋ ์ด๊ธฐ ๋ ๋๋ง ์ถ๋ ฅ์ ๋ณผ ๊ฒ์
๋๋ค. ๊ทธ๋ค์ ๋ก๋ฉ ๋ฐ hydration์ด ์๋ฃ๋๋ฉด Effect๊ฐ ์คํ๋์ด didMount
๋ฅผ true
๋ก ์ค์ ํ๋ฉด์ ๋ค์ ๋ ๋๋ง์ด ๋์ํฉ๋๋ค. ์ด๋ก์จ ํด๋ผ์ด์ธํธ ์ ์ฉ ๋ ๋๋ง ์ถ๋ ฅ์ผ๋ก ์ ํ๋ฉ๋๋ค. Effect๋ ์๋ฒ์์ ์คํ๋์ง ์์ผ๋ฏ๋ก ์ด๊ธฐ ์๋ฒ ๋ ๋๋ง ์ค์ didMount
๋ false
๊ฐ ๋ฉ๋๋ค.
์ด ํจํด์ ์ ์ ํ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๋๋ฆฐ ์ฐ๊ฒฐ ํ๊ฒฝ์ ๊ฐ์ง ์ฌ์ฉ์๋ ์ด๊ธฐ ๋ ๋๋ง ํ๋ฉด์ ์๋นํ ์๊ฐ ๋์ ๋ณผ ๊ฒ์ด๋ฏ๋ก ์ปดํฌ๋ํธ์ ๋ชจ์์ ๊ธ๋ณ์ํค์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ง์ ๊ฒฝ์ฐ์๋ CSS๋ฅผ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด๋ถ๋ก ๋ค์ํ ๊ฒ๋ค์ ํ์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋์ฒํ ์ ์์ต๋๋ค.
ํธ๋ฌ๋ธ ์ํ
Effect๊ฐ ์ปดํฌ๋ํธ ๋ง์ดํธ ์ 2๋ฒ ๋์ํฉ๋๋ค.
๊ฐ๋ฐ ํ๊ฒฝ์์ Strict Mode๊ฐ ํ์ฑํ๋๋ฉด React๋ ์ค์ ์ค์ ์ด์ ์ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ํ๋ฒ ๋ ์คํํฉ๋๋ค.
์ด๊ฒ์ Effect์ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์๋์ง ํ์ธํ๋ ์คํธ๋ ์ค ํ ์คํธ์ ๋๋ค. ์ด์ ๋ฐ๋ผ ๋์ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๋ฉด ์ ๋ฆฌ ํจ์์ ์ด๋ค ๋ก์ง์ด ๋๋ฝ๋์์ ์ ์์ต๋๋ค. ์ ๋ฆฌ ํจ์๋ ์ค์ ํจ์๊ฐ ์ํํ ๊ฒ์ ์ค์งํ๊ฑฐ๋ ๋๋๋ฆด ์ ์์ด์ผ ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ง์นจ์ผ๋ก๋ ์ฌ์ฉ์๊ฐ ์ค์ ์ด ํ๋ฒ ํธ์ถ๋๋ ๊ฒ(๋ฐฐํฌ ํ๊ฒฝ๊ณผ ๊ฐ์ด)๊ณผ ์ค์ โ ์ ๋ฆฌ โ ์ค์ ์์๋ก ํธ์ถ๋๋ ๊ฒ์ ๊ตฌ๋ณํ ์ ์์ด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ด ๋ฒ๊ทธ๋ฅผ ์ฐพ๋ ๋ฐ ์ด๋ป๊ฒ ๋์์ด ๋๋ฉฐ, ๋ก์ง์ ์ด๋ป๊ฒ ์์ ํ๋์ง์ ์์ธํ ์์๋ณด๋ ค๋ฉด ์ฌ๊ธฐ๋ฅผ ์ฝ์ด๋ณด์ธ์.
Effect๊ฐ ๋งค ๋ฆฌ๋ ๋๋ง๋ง๋ค ์คํ๋ฉ๋๋ค.
๋จผ์ ์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ ์ถ๊ฐํ๋์ง ํ์ธํด ๋ณด์ธ์.
useEffect(() => {
// ...
}); // ๐ฉ No dependency array: re-runs after every render!
์์กด์ฑ ๋ฐฐ์ด์ ๋ช ์ํ์์๋ Effect๊ฐ ์ฌ์ ํ ๋ฐ๋ณตํด์ ์คํ๋๋ค๋ฉด ์์กด์ฑ์ด ๋ ๋๋ง๋ง๋ค ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ์์ ์์กด์ฑ์ ์๋์ผ๋ก ๊ธฐ๋กํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋๋ฒ๊น ํ ์ ์์ต๋๋ค.
useEffect(() => {
// ..
}, [serverUrl, roomId]);
console.log([serverUrl, roomId]);
๊ทธ๋ค์ ์ฝ์์์ ๊ธฐ๋ก๋ ๋ค๋ฅธ ๋ ๋๋ง ๋ฐฐ์ด์ ๋ง์ฐ์ค ์ค๋ฅธ์ชฝ ๋ฒํผ์ผ๋ก ํด๋ฆญํ๊ณ ๋ ๋ฐฐ์ด ๋ชจ๋์ ๋ํด ์ ์ญ ๋ณ์๋ก ์ ์ฅ์ ์ ํํ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ์์๊ฐ temp1
์ด๊ณ ๋ ๋ฒ์งธ ์์๊ฐ temp2
๋ผ๊ณ ๊ฐ์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ฝ์์ ์ฌ์ฉํ์ฌ ์์ชฝ ๋ฐฐ์ด์ ๊ฐ ์์กด์ฑ์ด ๋์ผํ์ง ํ์ธํ ์ ์์ต๋๋ค.
Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays?
Object.is(temp1[1], temp2[1]); // Is the second dependency the same between the arrays?
Object.is(temp1[2], temp2[2]); // ... and so on for every dependency ...
๋ ๋๋ง๋ง๋ค ๋ค๋ฅธ ์์กด์ฑ์ ์ฐพ์๋๋ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก ๋ค์ ์ค ํ๋์ ๋ฐฉ๋ฒ์ผ๋ก ์์ ํ ์ ์์ต๋๋ค.
- Effect์์ ์ด์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก state ์ ๋ฐ์ดํธํ๊ธฐ
- ๋ถํ์ํ ๊ฐ์ฒด ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- ๋ถํ์ํ ํจ์ ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- Effect์์ ์ต์ props์ state๋ฅผ ์ฝ๊ธฐ
์ตํ์ ์๋จ์ผ๋ก (์ด๋ฌํ ๋ฐฉ๋ฒ๋ค์ด ๋์์ด ๋์ง ์์ ๊ฒฝ์ฐ), useMemo
๋ useCallback
(ํจ์์ ๊ฒฝ์ฐ)์ ์ด์ฉํ ์ ์์ต๋๋ค.
Effect๊ฐ ๋ฌดํ ๋ฐ๋ณต๋ฉ๋๋ค.
Effect๊ฐ ๋ฌดํ ๋ฐ๋ณต๋๋ ค๋ฉด ๋ค์ ๋ ๊ฐ์ง ์กฐ๊ฑด์ด ์ถฉ์กฑ๋์ด์ผ ํฉ๋๋ค..
- Effect์์ state๋ฅผ ์ ๋ฐ์ดํธํจ.
- ๋ณ๊ฒฝ๋ state๊ฐ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ๋ฉฐ, ์ด์ ๋ฐ๋ผ Effect์ ์ข ์์ฑ์ด ๋ณ๊ฒฝ๋จ.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ ์ Effect๊ฐ ์ธ๋ถ ์์คํ (DOM, ๋คํธ์ํฌ, ์๋ํํฐ ์์ ฏ ๋ฑ)์ ์ฐ๊ฒฐ๋์ด ์๋์ง ์ค์ค๋ก ์๋ฌธํด๋ณด์ธ์. Effect์์ ์ state๋ฅผ ๋ณ๊ฒฝํ๋์? ๋ณ๊ฒฝ๋ state๊ฐ ์ธ๋ถ ์์คํ ๊ณผ ๋๊ธฐํ๋๋์? ๋๋ Effect๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ ํ๋ฆ์ ๊ด๋ฆฌํ๋ ค๊ณ ํ๋ ๊ฑด๊ฐ์?
์ธ๋ถ ์์คํ ์ด ์๋ค๋ฉด Effect๋ฅผ ์ ๊ฑฐํด์ ๋ก์ง์ ๋จ์ํํ ์ ์๋์ง ๊ณ ๋ คํด๋ณด์ธ์.
๋ง์ฝ ์ค์ ๋ก ์ด๋ค ์ธ๋ถ ์์คํ ๊ณผ ๋๊ธฐํ ์ค์ด๋ผ๋ฉด Effect๊ฐ state๋ฅผ ์ธ์ ์ด๋ค ์กฐ๊ฑด์์ ์ ๋ฐ์ดํธํด์ผ ํ๋์ง์ ๋ํด ๊ณ ๋ คํด ๋ณด์ธ์. ์ปดํฌ๋ํธ์ ์๊ฐ์ ์ถ๋ ฅ์ ์ํฅ์ ์ฃผ๋ state๊ฐ ๋ณํ๋์? ๋ ๋๋ง์ ์ฌ์ฉ๋์ง ์๋ ๋ฐ์ดํฐ๋ฅผ ์ถ์ ํด์ผ ํ๋ค๋ฉด ๋ฆฌ๋ ๋๋ง์ ์ผ๊ธฐํ์ง ์๋ ref๊ฐ ๋ ์ ํฉํ ์ ์์ต๋๋ค. Effect๊ฐ ํ์ ์ด์์ผ๋ก state๋ฅผ ์ ๋ฐ์ดํธํ๋์ง(๋ฆฌ๋ ๋๋ง์ ์ผ๊ธฐํ์ง ์๋๋ก) ํ์ธํด ๋ณด์ธ์.
๋ง์ง๋ง์ผ๋ก Effect๊ฐ ์ ๋๋ก ๋ ์์ ์ state๋ฅผ ์ ๋ฐ์ดํธํ์ง๋ง ์ฌ์ ํ ๋ฌดํ ๋ฐ๋ณต๋๋ ๊ฒฝ์ฐ, ํด๋น state์ ์ ๋ฐ์ดํธ๊ฐ Effect์ ์ข ์์ฑ์ ๋ณ๊ฒฝ์ ์ผ๊ธฐํ์ ์ ์์ต๋๋ค. ์ข ์์ฑ ๋ณ๊ฒฝ์ ๋๋ฒ๊น ํ๋ ๋ฐฉ๋ฒ์ ์ฝ์ด๋ณด์ธ์.
์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋์ง ์์์์๋ ์ ๋ฆฌ ํจ์๊ฐ ์คํ๋ฉ๋๋ค.
์ ๋ฆฌ ํจ์๋ ๋ง์ดํธ ํด์ ์ ๋ฟ๋ง ์๋๋ผ ๋ณ๊ฒฝ๋ ์ข ์์ฑ์ผ๋ก ์ธํ ๋ชจ๋ ๋ฆฌ๋ ๋๋ง ์ ์ ์คํ๋ฉ๋๋ค. ๋ํ ๊ฐ๋ฐ ํ๊ฒฝ์์๋ React๊ฐ ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ์งํ์ ํ ๋ฒ ๋ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค.
์ค์ ์ฝ๋์ ์์ํ๋ ์ ๋ฆฌ ์ฝ๋๊ฐ ์๋ค๋ฉด ๋ณดํต์ ์ฝ๋์ ๋ฌธ์ ๊ฐ ์์ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.
useEffect(() => {
// ๐ด Avoid: Cleanup logic without corresponding setup logic
return () => {
doSomething();
};
}, []);
์ ๋ฆฌ ๋ก์ง์ ์ค์ ๋ก์ง๊ณผ โ๋์นญโ์ด์ด์ผ ํ๋ฉฐ ์ค์ ์ด ์ํํ ๊ฒ์ ์ค์งํ๊ฑฐ๋ ๋๋๋ฆด ์ ์์ด์ผ ํฉ๋๋ค.
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
Effect์ ์๋ช ์ฃผ๊ธฐ์ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ๊ฐ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง ํ์ธํด ๋ณด์ธ์.
Effect๊ฐ ์๊ฐ์ ์ธ ์์ ์ ์ํํ๋ฉฐ, ์คํ๋๊ธฐ ์ ์ ๊น๋นก์์ด ๋ณด์ ๋๋ค.
Effect๊ฐ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ๊ฒ
์ ์ฐจ๋จํด์ผ ํ๋ ๊ฒฝ์ฐ useEffect
๋ฅผ useLayoutEffect
๋ก ๋์ฒดํ์ธ์. ์ด๊ฒ์ ๋๋ถ๋ถ์ Effect์๋ ํ์ํ์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ํ์ธํ
์ด์ ์ Effect๋ฅผ ์คํํ๋ ๊ฒ์ด ์ค์ํ ๊ฒฝ์ฐ์๋ง ํ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ ์ ์ ํดํ์ ์์น๋ฅผ ์ธก์ ํ๊ณ ์ง์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.