useEffect
useEffect๋ ์ธ๋ถ ์์คํ
๊ณผ ์ปดํฌ๋ํธ๋ฅผ ๋๊ธฐํํ๋ React Hook์
๋๋ค.
useEffect(setup, dependencies?)- ๋ ํผ๋ฐ์ค
- ์ฌ์ฉ๋ฐฉ๋ฒ
- ์ธ๋ถ ์์คํ ๊ณผ ์ฐ๊ฒฐ
- ์ปค์คํ Hook์ Effect๋ก ๊ฐ์ธ๊ธฐ
- React๋ก ์์ฑ๋์ง ์์ ์์ ฏ ์ ์ดํ๊ธฐ
- Effect๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ํ์นญ
- ๋ฐ์ํ๊ฐ ์์กด์ฑ ์ง์
- Effect์์ ์ด์ state๋ฅผ ๊ธฐ๋ฐ์ผ๋ก state ์ ๋ฐ์ดํธํ๊ธฐ
- ๋ถํ์ํ ๊ฐ์ฒด ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- ๋ถํ์ํ ํจ์ ์์กด์ฑ ์ ๊ฑฐํ๊ธฐ
- Effect์์ ์ต์ props์ state๋ฅผ ์ฝ๊ธฐ
- ์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ์ปจํ ์ธ ๋ฅผ ํ์ํ๊ธฐ
- ํธ๋ฌ๋ธ ์ํ
- Effect๊ฐ ์ปดํฌ๋ํธ ๋ง์ดํธ ์ 2๋ฒ ๋์ํฉ๋๋ค.
- Effect๊ฐ ๋งค ๋ฆฌ๋ ๋๋ง๋ง๋ค ์คํ๋ฉ๋๋ค.
- Effect๊ฐ ๋ฌดํ ๋ฐ๋ณต๋ฉ๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋์ง ์์์์๋ ์ ๋ฆฌ ํจ์๊ฐ ์คํ๋ฉ๋๋ค.
- Effect๊ฐ ์๊ฐ์ ์ธ ์์ ์ ์ํํ๋ฉฐ, ์คํ๋๊ธฐ ์ ์ ๊น๋นก์์ด ๋ณด์ ๋๋ค.
๋ ํผ๋ฐ์ค
useEffect(setup, dependencies?)
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useEffect๋ฅผ ํธ์ถํ์ฌ Effect๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค.
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();
};
}, [serverUrl, roomId]);
// ...
}์๋์์ ๋ ๋ง์ ์์๋ฅผ ๋ณด์ธ์.
๋งค๊ฐ๋ณ์
-
setup(์ค์ ): Effect์ ๋ก์ง์ด ํฌํจ๋ ํจ์์ ๋๋ค. ์ค์ ํจ์๋ ์ ํ์ ์ผ๋ก clean up(์ ๋ฆฌ) ํจ์๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค. React๋ ์ปดํฌ๋ํธ๊ฐ DOM์ ์ถ๊ฐ๋ ์ดํ์ ์ค์ ํจ์๋ฅผ ์คํํฉ๋๋ค. ์์กด์ฑ์ ๋ณํ์ ๋ฐ๋ผ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง์ด ๋์์ ๊ฒฝ์ฐ, (์ค์ ํจ์์ ์ ๋ฆฌ ํจ์๋ฅผ ์ถ๊ฐํ์๋ค๋ฉด) React๋ ์ด์ ๋ ๋๋ง์ ์ฌ์ฉ๋ ๊ฐ์ผ๋ก ์ ๋ฆฌ ํจ์๋ฅผ ์คํํ ํ ์๋ก์ด ๊ฐ์ผ๋ก ์ค์ ํจ์๋ฅผ ์คํํฉ๋๋ค. ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋ ๊ฒฝ์ฐ์๋ ์ ๋ฆฌ ํจ์๋ฅผ ์คํํฉ๋๋ค. -
dependencies์ ํ์ฌํญ :์ค์ ํจ์์ ์ฝ๋ ๋ด๋ถ์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ๋ค์ด ํฌํจ๋ ๋ฐฐ์ด๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋ฐ์ํ ๊ฐ์๋ props์ state, ๋ชจ๋ ๋ณ์ ๋ฐ ์ปดํฌ๋ํธ body์ ์ง์ ์ ์ผ๋ก ์ ์ธ๋ ํจ์๋ค์ด ํฌํจ๋ฉ๋๋ค. ๋ฆฐํฐ๊ฐ React ํ๊ฒฝ์ ๋ง๊ฒ ์ค์ ๋์ด ์์ ๊ฒฝ์ฐ, ๋ฆฐํฐ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ๋ค์ด ์์กด์ฑ์ ์ ๋๋ก ๋ช ์๋์ด ์๋์ง ๊ฒ์ฆํ ๊ฒ์ ๋๋ค. ์์กด์ฑ ๋ฐฐ์ด์ ํญ์ ์ผ์ ํ ์์ ํญ๋ชฉ์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ฉฐ[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๊ฐ ์ฌ์ฉ์ ์ํธ์์ฉ(ํด๋ฆญ ๋ฑ)์ผ๋ก ์ธํด ๋ฐ์ํ ๊ฒฝ์ฐ, React๋ ํ๋ฉด์ด ์ ๋ฐ์ดํธ๋์ด ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ ์ Effect๋ฅผ ์คํํ ์ ์์ต๋๋ค. ์ด๊ฒ์ด Effect์ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฒคํธ ์์คํ ์ด ๊ด์ฐฐํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ๋๊ฐ ์์๋๋ก ์๋ํ์ง๋ง,
alert()์ ๊ฐ์ด ์์ ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฐ ํ๋ก ๋ฏธ๋ค์ผ ํ๋ ๊ฒฝ์ฐsetTimeout์ ํ์ฉํ ์ ์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ reactwg/react-18/128์ ์ฐธ์กฐํ์ธ์. -
Effect๊ฐ ์ฌ์ฉ์ ์ํธ์์ฉ(ํด๋ฆญ ๋ฑ)์ ์ํด ๋ฐ์ํ๋๋ผ๋, React๋ ๋๋ก Effect ๋ด๋ถ์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆฌ๋๋ก ํ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ๋๊ฐ ์์๋๋ก ์๋ํ์ง๋ง, ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆฌ์ง ์๋๋ก ๋ง์์ผ ํ๋ ์ํฉ์ด๋ผ๋ฉด
useEffect๋์useLayoutEffect๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. -
Effect๋ client ํ๊ฒฝ์์๋ง ๋์ํฉ๋๋ค. ์๋ฒ ๋ ๋๋ง์์๋ ๋์ํ์ง ์์ต๋๋ค.
์ฌ์ฉ๋ฐฉ๋ฒ
์ธ๋ถ ์์คํ ๊ณผ ์ฐ๊ฒฐ
๋ช๋ช ์ปดํฌ๋ํธ๋ค์ ํ์ด์ง์ ํ์๋๋ ๋์ ๋คํธ์ํฌ๋ ๋ธ๋ผ์ฐ์ API, ๋๋ ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฐ๊ฒฐ์ด ์ ์ง๋์ด์ผ ํฉ๋๋ค. React์ ์ ์ด๋์ง ์๋ ์ด๋ฌํ ์์คํ ๋ค์ ์ธ๋ถ ์์คํ (external) ์ด๋ผ ๋ถ๋ฆ ๋๋ค.
์ปดํฌ๋ํธ๋ฅผ ์ธ๋ถ ์์คํ
๊ณผ ์ฐ๊ฒฐํ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useEffect๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค.
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();
};
}, [serverUrl, roomId]);
// ...
}useEffect๋ 2๊ฐ์ ์ธ์๊ฐ ํ์ํฉ๋๋ค.
- ์ธ๋ถ ์์คํ
๊ณผ ์ปดํฌ๋ํธ๋ฅผ ์ฐ๊ฒฐํ๋ ์ค์ ์ฝ๋๊ฐ ํฌํจ๋ ์ค์ ํจ์
- ์ธ๋ถ ์์คํ ๊ณผ์ ์ฐ๊ฒฐ์ ํด์ ํ๋ ์ ๋ฆฌ ์ฝ๋๊ฐ ํฌํจ๋ ์ ๋ฆฌ ํจ์๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
- ์ ํจ์ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์์ ๋น๋กฏ๋ ๋ฐ์ํ ๊ฐ๋ค์ ํฌํจํ๋ ์์กด์ฑ ๋ฐฐ์ด
React๋ ์ค์ ํจ์์ ์ ๋ฆฌ ํจ์๊ฐ ํ์ํ ๋๋ง๋ค ํธ์ถํ ์ ์์ผ๋ฉฐ, ์ด๋ ์ฌ๋ฌ ๋ฒ ํธ์ถ๋ ์ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์ถ๊ฐ๋์์ ๋ ์ค์ ์ฝ๋๊ฐ ๋์ํฉ๋๋ค (๋ง์ดํธ ์).
- ์์กด์ฑ์ด ๋ณ๊ฒฝ๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋ ๋๋ง๋ค ์๋ ๋์์ ์ํํฉ๋๋ค.
- ๋จผ์ ์ ๋ฆฌ ์ฝ๋๊ฐ ์ค๋๋ props์ state์ ํจ๊ป ์คํ๋ฉ๋๋ค.
- ์ดํ, ์ค์ ์ฝ๋๊ฐ ์๋ก์ด props์ state์ ํจ๊ป ์คํ๋ฉ๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์์ ์ ๊ฑฐ๋ ์ดํ์ ์ ๋ฆฌ ์ฝ๋๊ฐ ๋ง์ง๋ง์ผ๋ก ์คํ๋ฉ๋๋ค (๋ง์ดํธ ํด์ ์).
์์ ์์๋ฅผ ํตํด ์์๋ฅผ ์ค๋ช ํด ๋ณด๊ฒ ์ต๋๋ค.
์์ ChatRoom ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ์ถ๊ฐ๋๋ฉด ์ด๊ธฐ serverUrl๊ณผ roomId๋ฅผ ์ด์ฉํด ์ฑํ
๋ฐฉ๊ณผ ์ฐ๊ฒฐ๋ ๊ฒ์
๋๋ค. ๋ฆฌ๋ ๋๋ง์ ์ํด serverUrl ๋๋ roomId๊ฐ ๋ณ๊ฒฝ๋๋ค๋ฉด (์๋ฅผ ๋ค์ด ์ฌ์ฉ์๊ฐ ๋๋กญ๋ค์ด ๋ฉ๋ด๋ฅผ ์ด์ฉํด ๋ค๋ฅธ ์ฑํ
๋ฐฉ์ ์ ํํ ๊ฒฝ์ฐ) Effect๋ ์ด์ ์ฑํ
๋ฐฉ๊ณผ์ ์ฐ๊ฒฐ์ ํด์ ํ๊ณ ๋ค์ ์ฑํ
๋ฐฉ๊ณผ ์ฐ๊ฒฐํฉ๋๋ค. ChatRoom ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์์ ์ ๊ฑฐ๋๋ค๋ฉด Effect๋ ๋ง์ง๋ง ์ฑํ
๋ฐฉ๊ณผ ์ด๋ค์ง ์ฐ๊ฒฐ์ ํด์ ํ ๊ฒ์
๋๋ค.
React๋ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ชจ๋์์ ์ค์ ์ด ์คํ๋๊ธฐ ์ ์ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ํ ๋ฒ ๋ ์คํ์ํต๋๋ค. ์ด๋ ์คํธ๋ ์ค ํ ์คํธ์ ํ๋๋ก์จ 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} />} </> ); }
React๋ก ์์ฑ๋์ง ์์ ์์ ฏ ์ ์ดํ๊ธฐ
๊ฐ๋์ ์ปดํฌ๋ํธ์ prop ๋๋ state๋ฅผ ์ธ๋ถ ์์คํ ๊ณผ ๋๊ธฐํํด์ผํ ๋๊ฐ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด React ์์ด ์์ฑ๋ ์๋ ํํฐ ์ง๋ ์์ ฏ์ด๋ ๋น๋์ค ํ๋ ์ด์ด ์ปดํฌ๋ํธ๊ฐ ์๋ค๋ฉด ์ด ์ปดํฌ๋ํธ์ 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๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ํ์นญ
You can use an Effect to fetch data for your component. Note that if you use a framework, using your frameworkโs data fetching mechanism will be a lot more efficient than writing Effects manually.
๋ง์ฝ ์ง์ 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์ ์ฌ์ฉํ๋ ํธ์ด ๋ ๊ฐ๋จํฉ๋๋ค.
์์ธํ ์ดํด๋ณด๊ธฐ
Effect ๋ด๋ถ์์ fetch ํธ์ถ์ ์์ฑํ๋ ๊ฒ์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์ฑ์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ๋ฐฉ๋ฒ์
๋๋ค. ํ์ง๋ง ์ด๊ฒ์ ๋งค์ฐ ์๋์ ์ธ ์ ๊ทผ ๋ฐฉ์์ด๋ฉฐ ํฐ ๋จ์ ์ด ์์ต๋๋ค.
- Effect๋ ์๋ฒ์์๋ ์คํ๋์ง ์์ต๋๋ค. ์ด๋ ์ด๊ธฐ ์๋ฒ ๋ ๋๋ง ๋ HTML์ด ๋ฐ์ดํฐ๊ฐ ์๋ state๋ง์ ํฌํจํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ํด๋ผ์ด์ธํธ ์ปดํจํฐ๋ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ด๋ก๋ ๋ฐ๊ณ ์ฑ์ ๋ ๋๋งํ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค. ์ด๋ ํจ์จ์ ์ด์ง ์์ ์ ์์ต๋๋ค.
- Effect ๋ด๋ถ์์ ์ง์ ํ์นญ์ ํ๋ ๊ฒ์ ๋คํธ์ํฌ ํญํฌ(network waterfalls)๊ฐ ์์ฑ๋๊ธฐ ์ฝ๊ฒ ํฉ๋๋ค. ๋ถ๋ชจ ์ปดํฌ๋ํธ ๋ ๋๋ง ํ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ณ ๋์ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ฉ๋๋ค. ์ดํ ์์ ์ปดํฌ๋ํธ๊ฐ ์์ ์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ธฐ ์์ํฉ๋๋ค. ๋คํธ์ํฌ์ ์๋๊ฐ ๋น ๋ฅด์ง ์๋ค๋ฉด ์ด ๋ฐฉ๋ฒ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ํ์นญํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋๋ฆฝ๋๋ค.
- Effect ๋ด๋ถ์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฒ์ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ก๋ํ๊ฑฐ๋ ์บ์ฑํ์ง ์๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋๊ณ ๋ค์ ๋ง์ดํธ๋์์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์์ผ ํฉ๋๋ค.
- ์ฌ์ฉํ๊ธฐ ๋งค์ฐ ๋ถํธํ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ฒฝ์ ์กฐ๊ฑด๊ณผ ๊ฐ์ ๋ฒ๊ทธ๋ฅผ ๋ฐ์์ํค์ง ์๋๋ก fetch ํธ์ถ์ ์์ฑํ ๋ ์๋นํ ์์ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค.
์ด๋ฌํ ๋จ์ ์ React๋ง ํด๋น๋๋ ๊ฒ์ด ์๋๋๋ค. ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ ๋๋ ํด๋น๋ฉ๋๋ค. ๋ผ์ฐํ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ์ดํฐ ํ์นญ์ ์ธ๋ถ์ ์ธ ์ฌํญ์ด ๋ง์ผ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ ์ ๊ทผ ๋ฐฉ์์ ๊ถ์ฅํฉ๋๋ค.
- If you use a framework, use its built-in data fetching mechanism. Modern React frameworks have integrated data fetching mechanisms that are efficient and donโt suffer from the above pitfalls.
- Otherwise, consider using or building a client-side cache. Popular open source solutions include React Query, useSWR, and React Router 6.4+. You can build your own solution too, in which case you would use Effects under the hood but also add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes).
๋ง์ฝ ์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ด ์ ํฉํ์ง ์๋ค๋ฉด Effect ๋ด๋ถ์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฒ์ ๊ณ์ ์งํํ ์ ์์ต๋๋ค.
๋ฐ์ํ๊ฐ ์์กด์ฑ ์ง์
Effect์ ์์กด์ฑ์ โ์ ํโํ ์ ์๋ค๋ ์ ์ ์ ์ํ์ธ์. Effect ์ฝ๋์์ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ์์กด์ฑ์ผ๋ก ์ ์ธ๋์ด์ผ ํฉ๋๋ค. Effect์ ์์กด์ฑ ๋ฐฐ์ด์ ์ฝ๋์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค.
function ChatRoom({ roomId }) { // ์ด๊ฒ์ ๋ฐ์ํ ๊ฐ์
๋๋ค
const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // ์ด๊ฒ๋ ๋ฐ์ํ ๊ฐ์
๋๋ค
useEffect(() => {
const connection = createConnection(serverUrl, roomId); // ์ด Effect๋ ์ด ๋ฐ์ํ ๊ฐ๋ค์ ์ฝ์ต๋๋ค
connection.connect();
return () => connection.disconnect();
}, [serverUrl, roomId]); // โ
๊ทธ๋์ ์ด ๊ฐ๋ค์ Effect์ ์์กด์ฑ์ผ๋ก ์ง์ ํด์ผ ํฉ๋๋ค
// ...
}serverUrl ๋๋ roomId๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค Effect๋ ์๋ก์ด ๊ฐ์ ์ด์ฉํด ์ฑํ
์ ๋ค์ ์ฐ๊ฒฐํ ๊ฒ์
๋๋ค.
๋ฐ์ํ ๊ฐ ์๋ props์ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ ์ธ๋ ๋ชจ๋ ๋ณ์๋ ํจ์๋ค์ด ํฌํจ๋ฉ๋๋ค. roomId์ serverUrl์ ๋ฐ์ํ ๊ฐ์ด๋ฏ๋ก ์ด๋ค์ ์์กด์ฑ์์ ์ ๊ฑฐํ๋ฉด ์ ๋ฉ๋๋ค. ์ด๋ค์ ๋๋ฝํ์ ๋ ๋ฆฐํฐ๊ฐ React ํ๊ฒฝ์ ๋ง๊ฒ ์ค์ ๋์ด ์์๋ค๋ฉด ๋ฆฐํฐ๋ ์ด๊ฒ์ ์์ ํด์ผ ํ๋ ์ค์๋ก ํ์ํฉ๋๋ค.
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'; // ๋ ์ด์ ๋ฐ์ํ ๊ฐ์ด ์๋
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // โ
๋ชจ๋ ์์กด์ฑ์ด ์ ์ธ๋จ
// ...
}์ด์ serverUrl์ ๋ฐ์ํ ๊ฐ์ด ์๋๋ฉฐ (๋ฆฌ๋ ๋๋ง๋ ๋ ๋ณ๊ฒฝ๋์ง ์์ ๊ฒ์ด๋ฏ๋ก), ์์กด์ฑ์ ์ถ๊ฐํ ํ์๊ฐ ์์ต๋๋ค. Effect์ ์ฝ๋๊ฐ ์ด๋ค ๋ฐ์ํ ๊ฐ๋ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ๊ทธ ์์กด์ฑ ๋ชฉ๋ก์ ๋น์ด์์ด์ผ ํฉ๋๋ค. ([])
const serverUrl = 'https://localhost:1234'; // ๋ ์ด์ ๋ฐ์ํ ๊ฐ์ด ์๋
const roomId = 'music'; // ๋ ์ด์ ๋ฐ์ํ ๊ฐ์ด ์๋
function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // โ
๋ชจ๋ ์์กด์ฑ์ด ์ ์ธ๋จ
// ...
}์์กด์ฑ์ด ๋น์ด์๋ Effect๋ ์ปดํฌ๋ํธ์ props๋ state๊ฐ ๋ณ๊ฒฝ๋๋ ๋ค์ ์คํ๋์ง ์์ต๋๋ค.
์์ 1 of 3: ์์กด์ฑ ๋ฐฐ์ด ์ ๋ฌ
์์กด์ฑ์ ๋ช ์ํ๋ฉด Effect๋ ์ด๊ธฐ ๋ ๋๋ง ํ ๊ทธ๋ฆฌ๊ณ ์์กด์ฑ ๊ฐ ๋ณ๊ฒฝ๊ณผ ํจ๊ป ๋ฆฌ๋ ๋๋ง์ด ๋ ํ ๋์ํฉ๋๋ค.
useEffect(() => {
// ...
}, [a, b]); // a๋ b๊ฐ ๋ค๋ฅด๋ฉด ๋ค์ ์คํ๋จ์๋ ์์์์๋ 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); // ์ด๋ง๋ค ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํค๊ณ ์ถ์ต๋๋ค...
}, 1000)
return () => clearInterval(intervalId);
}, [count]); // ๐ฉ ... ํ์ง๋ง 'count'๋ฅผ ์์กด์ฑ์ผ๋ก ๋ช
์ํ๋ฉด ํญ์ ์ธํฐ๋ฒ์ด ์ด๊ธฐํ๋ฉ๋๋ค.
// ...
}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); // โ State ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ }, 1000); return () => clearInterval(intervalId); }, []); // โ ์ด์ count๋ ์์กด์ฑ์ด ์๋๋๋ค 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 = { // ๐ฉ ์ด ๊ฐ์ฒด๋ ์ฌ ๋ ๋๋ง ๋ ๋๋ง๋ค ์๋ก ์์ฑ๋ฉ๋๋ค
serverUrl: serverUrl,
roomId: roomId
};
useEffect(() => {
const connection = createConnection(options); // ๊ฐ์ฒด๊ฐ Effect ์์์ ์ฌ์ฉ๋ฉ๋๋ค
connection.connect();
return () => connection.disconnect();
}, [options]); // ๐ฉ ๊ฒฐ๊ณผ์ ์ผ๋ก, ์์กด์ฑ์ด ์ฌ ๋ ๋๋ง ๋๋ง๋ค ๋ค๋ฆ
๋๋ค
// ...๋ ๋๋ง ์ค์ ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ์์กด์ฑ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ํผํ์ธ์. ๋์ ๊ฐ์ฒด๋ฅผ 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() { // ๐ฉ ์ด ํจ์๋ ์ฌ ๋ ๋๋ง ๋ ๋๋ง๋ค ์๋ก ์์ฑ๋ฉ๋๋ค
return {
serverUrl: serverUrl,
roomId: roomId
};
}
useEffect(() => {
const options = createOptions(); // ํจ์๊ฐ Effect ์์์ ์ฌ์ฉ๋ฉ๋๋ค
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // ๐ฉ ๊ฒฐ๊ณผ์ ์ผ๋ก, ์์กด์ฑ์ด ์ฌ ๋ ๋๋ง ๋๋ง๋ค ๋ค๋ฆ
๋๋ค
// ...๋ฆฌ๋ ๋๋ง๋ง๋ค ํจ์๋ฅผ ์ฒ์๋ถํฐ ์์ฑํ๋ ๊ฒ ๊ทธ ์์ฒด๋ก๋ ๋ฌธ์ ๊ฐ ๋์ง ์๊ณ , ์ด๋ฅผ ์ต์ ํํ ํ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ฒ์ 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๋ฅผ ์ฝ๊ธฐ
By default, when you read a reactive value from an Effect, you have to add it as a dependency. This ensures that your Effect โreactsโ to every change of that value. For most dependencies, thatโs the behavior you want.
๊ทธ๋ฌ๋ ๋๋ก๋ Effect์์ ์ต์ props์ state๋ฅผ โ๋ฐ์โํ์ง ์๊ณ ์ฝ๊ณ ์ถ์ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํ์ด์ง ๋ฐฉ๋ฌธ๋ง๋ค ์ผํ ์นดํธ์ ๋ด๊ธด ํญ๋ชฉ ์๋ฅผ ๊ธฐ๋กํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
function Page({ url, shoppingCart }) {
useEffect(() => {
logVisit(url, shoppingCart.length);
}, [url, shoppingCart]); // โ
๋ชจ๋ ์์กด์ฑ์ด ์ ์ธ๋จ
// ...
}What if you want to log a new page visit after every url change, but not if only the shoppingCart changes? You canโt exclude shoppingCart from dependencies without breaking the reactivity rules. However, you can express that you donโt want a piece of code to โreactโ to changes even though it is called from inside an Effect. Declare an Effect Event with the useEffectEvent Hook, and move the code reading shoppingCart inside of it:
function Page({ url, shoppingCart }) {
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, shoppingCart.length)
});
useEffect(() => {
onVisit(url);
}, [url]); // โ
๋ชจ๋ ์์กด์ฑ์ด ์ ์ธ๋จ
// ...
}Effect ์ด๋ฒคํธ๋ ๋ฐ์์ ์ด์ง ์์ผ๋ฉฐ Effect์ ์์กด์ฑ์์ ๋ฐฐ์ ๋์ด์ผ ํฉ๋๋ค. Effect ์ด๋ฒคํธ์๋ ๋น ๋ฐ์ํ ์ฝ๋(Effect ์ด๋ฒคํธ ๋ก์ง์ ์ต์ props์ state๋ฅผ ์ฝ์ ์ ์์)๋ฅผ ๋ฐฐ์นํ ์ ์์ต๋๋ค. onVisit๋ด์ shoppingCart๋ฅผ ์ฝ์์ผ๋ก์จ shoppingCart์ ๋ณ๊ฒฝ์ผ๋ก ์ธํ Effect์ ์ฌ์คํ์ ๋ฐฉ์งํฉ๋๋ค.
์๋ฒ์ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ์ปจํ ์ธ ๋ฅผ ํ์ํ๊ธฐ
If your app uses server rendering (either directly or via a framework), your component will render in two different environments. On the server, it will render to produce the initial HTML. On the client, React will run the rendering code again so that it can attach your event handlers to that HTML. This is why, for hydration to work, your initial render output must be identical on the client and the server.
๋๋ฌผ๊ฒ ํด๋ผ์ด์ธํธ์์ ๋ค๋ฅธ ๋ด์ฉ์ ํ์ํด์ผ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ฑ์ด localStorage์์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๊ฒฝ์ฐ, ์ด๋ฅผ ์๋ฒ์์ ๊ตฌํํ ์ ์์ต๋๋ค. ๋ค์์ ์ด๊ฒ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
function MyComponent() {
const [didMount, setDidMount] = useState(false);
useEffect(() => {
setDidMount(true);
}, []);
if (didMount) {
// ... ํด๋ผ์ด์ธํธ ์ ์ฉ JSX ๋ฐํ ...
} else {
// ... ์ด๊ธฐ JSX ๋ฐํ ...
}
}์ฑ์ด ๋ก๋ฉ ์ค์ธ ๋์ ์ฌ์ฉ์๋ ์ด๊ธฐ ๋ ๋๋ง ์ถ๋ ฅ์ ๋ณผ ๊ฒ์
๋๋ค. ๊ทธ๋ค์ ๋ก๋ฉ ๋ฐ hydration์ด ์๋ฃ๋๋ฉด Effect๊ฐ ์คํ๋์ด didMount๋ฅผ true๋ก ์ค์ ํ๋ฉด์ ๋ค์ ๋ ๋๋ง์ด ๋์ํฉ๋๋ค. ์ด๋ก์จ ํด๋ผ์ด์ธํธ ์ ์ฉ ๋ ๋๋ง ์ถ๋ ฅ์ผ๋ก ์ ํ๋ฉ๋๋ค. Effect๋ ์๋ฒ์์ ์คํ๋์ง ์์ผ๋ฏ๋ก ์ด๊ธฐ ์๋ฒ ๋ ๋๋ง ์ค์ didMount๋ false๊ฐ ๋ฉ๋๋ค.
์ด ํจํด์ ์ ์ ํ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๋๋ฆฐ ์ฐ๊ฒฐ ํ๊ฒฝ์ ๊ฐ์ง ์ฌ์ฉ์๋ ์ด๊ธฐ ๋ ๋๋ง ํ๋ฉด์ ์๋นํ ์๊ฐ ๋์ ๋ณผ ๊ฒ์ด๋ฏ๋ก ์ปดํฌ๋ํธ์ ๋ชจ์์ ๊ธ๋ณ์ํค์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ง์ ๊ฒฝ์ฐ์๋ CSS๋ฅผ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด๋ถ๋ก ๋ค์ํ ๊ฒ๋ค์ ํ์ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋์ฒํ ์ ์์ต๋๋ค.
ํธ๋ฌ๋ธ ์ํ
Effect๊ฐ ์ปดํฌ๋ํธ ๋ง์ดํธ ์ 2๋ฒ ๋์ํฉ๋๋ค.
๊ฐ๋ฐ ํ๊ฒฝ์์ Strict Mode๊ฐ ํ์ฑํ๋๋ฉด React๋ ์ค์ ์ค์ ์ด์ ์ ์ค์ ๊ณผ ์ ๋ฆฌ๋ฅผ ํ๋ฒ ๋ ์คํํฉ๋๋ค.
์ด๊ฒ์ Effect์ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์๋์ง ํ์ธํ๋ ์คํธ๋ ์ค ํ ์คํธ์ ๋๋ค. ์ด์ ๋ฐ๋ผ ๋์ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๋ฉด ์ ๋ฆฌ ํจ์์ ์ด๋ค ๋ก์ง์ด ๋๋ฝ๋์์ ์ ์์ต๋๋ค. ์ ๋ฆฌ ํจ์๋ ์ค์ ํจ์๊ฐ ์ํํ ๊ฒ์ ์ค์งํ๊ฑฐ๋ ๋๋๋ฆด ์ ์์ด์ผ ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ง์นจ์ผ๋ก๋ ์ฌ์ฉ์๊ฐ ์ค์ ์ด ํ๋ฒ ํธ์ถ๋๋ ๊ฒ(๋ฐฐํฌ ํ๊ฒฝ๊ณผ ๊ฐ์ด)๊ณผ ์ค์ โ ์ ๋ฆฌ โ ์ค์ ์์๋ก ํธ์ถ๋๋ ๊ฒ์ ๊ตฌ๋ณํ ์ ์์ด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ด ๋ฒ๊ทธ๋ฅผ ์ฐพ๋ ๋ฐ ์ด๋ป๊ฒ ๋์์ด ๋๋ฉฐ, ๋ก์ง์ ์ด๋ป๊ฒ ์์ ํ๋์ง์ ์์ธํ ์์๋ณด๋ ค๋ฉด ์ฌ๊ธฐ๋ฅผ ์ฝ์ด๋ณด์ธ์.
Effect๊ฐ ๋งค ๋ฆฌ๋ ๋๋ง๋ง๋ค ์คํ๋ฉ๋๋ค.
๋จผ์ ์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ ์ถ๊ฐํ๋์ง ํ์ธํด ๋ณด์ธ์.
useEffect(() => {
// ...
}); // ๐ฉ ์์กด์ฑ ๋ฐฐ์ด์ด ์์. ์ฌ ๋ ๋๋ง ๋ ๋๋ง๋ค ์ฌ์คํ๋จ!์์กด์ฑ ๋ฐฐ์ด์ ๋ช ์ํ์์๋ Effect๊ฐ ์ฌ์ ํ ๋ฐ๋ณตํด์ ์คํ๋๋ค๋ฉด ์์กด์ฑ์ด ๋ ๋๋ง๋ง๋ค ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ์์ ์์กด์ฑ์ ์๋์ผ๋ก ๊ธฐ๋กํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋๋ฒ๊น ํ ์ ์์ต๋๋ค.
useEffect(() => {
// ..
}, [serverUrl, roomId]);
console.log([serverUrl, roomId]);๊ทธ๋ค์ ์ฝ์์์ ๊ธฐ๋ก๋ ๋ค๋ฅธ ๋ ๋๋ง ๋ฐฐ์ด์ ๋ง์ฐ์ค ์ค๋ฅธ์ชฝ ๋ฒํผ์ผ๋ก ํด๋ฆญํ๊ณ ๋ ๋ฐฐ์ด ๋ชจ๋์ ๋ํด ์ ์ญ ๋ณ์๋ก ์ ์ฅ์ ์ ํํ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ์์๊ฐ temp1์ด๊ณ ๋ ๋ฒ์งธ ์์๊ฐ temp2๋ผ๊ณ ๊ฐ์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ฝ์์ ์ฌ์ฉํ์ฌ ์์ชฝ ๋ฐฐ์ด์ ๊ฐ ์์กด์ฑ์ด ๋์ผํ์ง ํ์ธํ ์ ์์ต๋๋ค.
Object.is(temp1[0], temp2[0]); // ์ฒซ ๋ฒ์งธ ์์กด์ฑ์ด ๋ฐฐ์ด ๊ฐ์ ๋์ผํ๊ฐ์?
Object.is(temp1[1], temp2[1]); // ๋ ๋ฒ์งธ ์์กด์ฑ์ด ๋ฐฐ์ด ๊ฐ์ ๋์ผํ๊ฐ์?
Object.is(temp1[2], temp2[2]); // ... ๋๋จธ์ง ๋ชจ๋ ์์กด์ฑ๋ ํ์ธํฉ๋๋ค ...๋ ๋๋ง๋ง๋ค ๋ค๋ฅธ ์์กด์ฑ์ ์ฐพ์๋๋ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก ๋ค์ ์ค ํ๋์ ๋ฐฉ๋ฒ์ผ๋ก ์์ ํ ์ ์์ต๋๋ค.
- 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(() => {
// ๐ด ํผํ์ธ์: ์์ํ๋ ์ค์ ๋ก์ง์ด ์๋ ์ ๋ฆฌ ๋ก์ง
return () => {
doSomething();
};
}, []);์ ๋ฆฌ ๋ก์ง์ ์ค์ ๋ก์ง๊ณผ โ๋์นญโ์ด์ด์ผ ํ๋ฉฐ ์ค์ ์ด ์ํํ ๊ฒ์ ์ค์งํ๊ฑฐ๋ ๋๋๋ฆด ์ ์์ด์ผ ํฉ๋๋ค.
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);Effect์ ์๋ช ์ฃผ๊ธฐ์ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ๊ฐ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง ํ์ธํด ๋ณด์ธ์.
Effect๊ฐ ์๊ฐ์ ์ธ ์์ ์ ์ํํ๋ฉฐ, ์คํ๋๊ธฐ ์ ์ ๊น๋นก์์ด ๋ณด์ ๋๋ค.
Effect๊ฐ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ๊ฒ์ ์ฐจ๋จํด์ผ ํ๋ ๊ฒฝ์ฐ useEffect๋ฅผ useLayoutEffect๋ก ๋์ฒดํ์ธ์. ์ด๊ฒ์ ๋๋ถ๋ถ์ Effect์๋ ํ์ํ์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ํ์ธํ
์ด์ ์ Effect๋ฅผ ์คํํ๋ ๊ฒ์ด ์ค์ํ ๊ฒฝ์ฐ์๋ง ํ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ ์ ์ ํดํ์ ์์น๋ฅผ ์ธก์ ํ๊ณ ์ง์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.