05. ๐ช ๋ฆฌ์กํธ ํ ๊ณผ ๊ด์ฌ์ฌ ๋ถ๋ฆฌ ์ค๊ณ
๐ ๊ฐ์
์ปค์คํ ํ ์ ํตํ ๋น์ฆ๋์ค ๋ก์ง ๋ถ๋ฆฌ์, ์ธ๋ถ ์ํ ๊ตฌ๋ ์ ๋ฐ์ํ๋ ํ ์ด๋ง ํ์์ ๋ฐฉ์งํ๋ ๊ณ ๊ธ ํ ์ค๊ณ ๊ธฐ์ ์ ์ ๋ณตํฉ๋๋ค.
๐ ์ด ๋ฉด์ ํญ๋ชฉ์ ๋ชฉํ
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 22๋ถ (ํต์ฌ ์์ฝ: 11๋ถ)
๐บ๏ธ ์ด ์ฑํฐ์ ํ๋ฆ
[๊ฐ๋
์ฌ์ ] โ [์ง๋ฌธ 1: ๋ก์ง ๋ถ๋ฆฌ ๊ธฐ์ค] โ [์ง๋ฌธ 2: useSyncExternalStore] โ [์ค์ ๋ณํ ์ง๋ฌธ]
๐ฏ ์ด ์ฑํฐ๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ๋ทฐ(View)์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๋ช ํํ ๊ธฐ์ค์ ์ธ์ธ ์ ์์ต๋๋ค.
useSyncExternalStore๋ฅผ ์ฌ์ฉํด ์ธ๋ถ ์ํ๋ฅผ ์์ ํ๊ฒ ๊ตฌ๋ ํ๋ ๋ฒ์ ์ดํดํฉ๋๋ค.- HOC์ ์ปค์คํ ํ ํจํด์ ์ ์ฌ์ ์ ํ์ฉ๋ฒ์ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋น๊ตํฉ๋๋ค.
๐ ํต์ฌ ๊ฐ๋ ์ฌ์ (Concept Glossary)
1. ๊ด์ฌ์ฌ ๋ถ๋ฆฌ (Separation of Concerns, SoC)
ํ๋์ ์ปดํฌ๋ํธ๋ ํจ์๊ฐ ํ๋์ ๋ชฉ์ ์๋ง ์ง์คํ๋๋ก ๋ง๋๋ ์ค๊ณ ์์น์ ๋๋ค. ๋ฆฌ์กํธ์์๋ ์ฃผ๋ก UI๋ฅผ ๋ด๋นํ๋ ๋ทฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๋ฐ ์ง์คํฉ๋๋ค.
2. ํ ์ด๋ง (Tearing)
๋์์ฑ ๋ ๋๋ง ํ๊ฒฝ์์ ํ๋ฉด์ ์ฌ๋ฌ ๋ถ๋ถ์ด ์๋ก ๋ค๋ฅธ ์์ ์ ์ํ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์๊ฐ์ ๋ถ์ผ์น ํ์์ ๋๋ค. ๋ ๋๋ง ๋์ค ์ธ๋ถ ์ํ(Store ๋ฑ)๊ฐ ๋ฐ๋์ด ๋ฐ์ํฉ๋๋ค.
3. ๊ณ ์ฐจ ์ปดํฌ๋ํธ (Higher-Order Component, HOC)
์ปดํฌ๋ํธ๋ฅผ ์ธ์๋ก ๋ฐ์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํ๋ ํจํด์ ๋๋ค. ํ ์ด ๋ฑ์ฅํ๊ธฐ ์ ๋ก์ง ์ฌ์ฌ์ฉ์ ํต์ฌ์ด์์ผ๋ฉฐ, ํ์ฌ๋ ๋ก๊น ์ด๋ ๊ถํ ์ฒดํฌ ๋ฑ UI๋ฅผ ๊ฐ์ธ๋ ๋ก์ง์ ์ฃผ๋ก ์ฐ์ ๋๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ๐ฃ ์์ฒ ( ์ ์ ): "์ํธ ๋! '์์๋ค ๋์๋ณด๋' ์ปดํฌ๋ํธ๊ฐ 500์ค์ด ๋์ด๊ฐ์ ๋์ ํ ๋ชป ๊ณ ์น๊ฒ ์ด์. ์์ API ํธ์ถ, ์ ๋ ฌ ๋ก์ง, ํํฐ ๋ก์ง์ด ๋ค ์์ฌ ์์ด์ ํ๋ ๋ฐ๊พธ๋ฉด ๋ค ํฐ์ ธ์! ๐ญ"
- ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "์์ฒ ๋, ๊ทธ๊ฒ ๋ฐ๋ก '์คํ๊ฒํฐ ์ปดํฌ๋ํธ'์ ์ ํ์ ๋๋ค. ์ปดํฌ๋ํธ๋ UI๋ง ๊ทธ๋ ค์ผ ํด์. ๊ณ์ฐ๊ธฐ ์์ง์ด๋ ๊ป๋ฐ๊ธฐ๋ฅผ ๋ถ๋ฆฌํ์ง ์์ผ๋ฉด ํ์ ์ ์ง๋ณด์์ ๋ช์์ ๋ชป ๋์ฌ ๊ฒ๋๋ค. ์, ์ปค์คํ ํ ์ผ๋ก '๋'๋ฅผ ์ถ์ถํด ๋ด ์๋ค."
Q1. ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ์ํด ๋น์ฆ๋์ค ๋ก์ง์ ์ปค์คํ ํ ์ผ๋ก ์ถ์ถํ ๋, ๋ทฐ(View)์ ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๊ธฐ์ค์ ๋ฌด์์ธ๊ฐ์?
๐ฏ ์ถ์ ์๋
์ฝ๋๋ฅผ ๋จ์ํ ์ฎ๊ธฐ๋ ํ์๋ฅผ ๋์ด, ์ปดํฌ๋ํธ์ ์ฑ ์์ ์ด๋ป๊ฒ ์ ์ํ๋์ง ๊ทธ๋ฆฌ๊ณ ์ฌ์ฌ์ฉ์ฑ๊ณผ ํ ์คํธ ์ฉ์ด์ฑ์ ๊ณ ๋ คํ ์ค๊ณ ์ฒ ํ์ด ์๋์ง ํ์ธํฉ๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ ์ปดํฌ๋ํธ ์์ ๋ชจ๋ ๊ฒ์ ๋ค ๋๋ ค ๋ฐ์์ต๋๋ค.
// ๐ฃ ์์ฒ : "์ฐพ์๋ณด๊ธฐ ํธํ๊ฒ ํ ํ์ผ์ ๋ค ๋ชจ์๋จ์ด์!"
function UserDashboard() {
const [data, setData] = useState([]);
useEffect(() => {
// โ ๏ธ API ํธ์ถ ๋ก์ง ์ง์ ๋
ธ์ถ
fetch('/api/users').then(res => res.json()).then(setData);
}, []);
// โ ๏ธ ๋ณต์กํ ํํฐ/์ ๋ ฌ ๋ก์ง ์ง์ ๋
ธ์ถ
const sortedData = [...data].sort((a, b) => b.score - a.score);
const activeUsers = sortedData.filter(u => u.isActive);
return (
<div>
{activeUsers.map(user => <UserItem key={user.id} {...user} />)}
</div>
);
}๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋, ์ด๋ ๊ฒ ์ง๋ฉด '๋ฐ์ดํฐ ํํฐ๋ง ๋ก์ง'๋ง ๋ฐ๋ก ํ ์คํธํ๊ณ ์ถ์ ๋ ์ปดํฌ๋ํธ ์ ์ฒด๋ฅผ ๋ ๋๋งํด์ผ ํด์. ์ปดํฌ๋ํธ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ ๊ทธ๋ฆผ์ ๊ทธ๋ฆฌ๋ ๊ฒ์๋ง ์ง์คํด์ผ ํฉ๋๋ค. ๋๋จธ์ง๋ ๋ค ํ ์ผ๋ก ์ ๋ฐฐ ๋ณด๋ด์ธ์."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๋ ๋น์ฆ๋์ค ๋ก์ง์ useUserBoard๋ผ๋ ์ปค์คํ
ํ
์ผ๋ก ๋ถ๋ฆฌํฉ๋๋ค.
// ๐ฆ ์ํธ: "์ปดํฌ๋ํธ๋ UI ๋ช
์ธ์์ฌ์ผ ํฉ๋๋ค. ์์ธ ๋ก์ง์ ํ
์ด๋ผ๋ ํ์ฒญ์
์ฒด์ ๋งก๊ธฐ์ธ์."
// ๐ง Business Logic Hook
function useUserBoard() {
const [users, setUsers] = useState([]);
// ... fetch users๋ก์ง
const processUsers = (data) => {
return data
.sort((a, b) => b.score - a.score)
.filter(u => u.isActive);
};
return { users: processUsers(users) };
}
// ๐ผ๏ธ View Component
function UserDashboard() {
const { users } = useUserBoard(); // ๐ช ๋ง๋ฒ์ฒ๋ผ ๋ฐ์ดํฐ๋ง ์!
return (
<div>
{users.map(user => <UserItem key={user.id} {...user} />)}
</div>
);
}๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "์ฌ์ฌ์ฉํ๊ณ ์ถ์ ๋ก์ง์ด ์๊ธฐ๋ฉด ์ปค์คํ ํ ์ผ๋ก ๋ง๋ญ๋๋ค. ์ปดํฌ๋ํธ ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ง ๋๋ ๋ถ๋ฆฌํฉ๋๋ค."
- Level 2 (Senior): "๋ฐ์ดํฐ ํ์นญ, ์ํ ๊ด๋ฆฌ, ๋ณต์กํ ์ฐ์ฐ ๋ฑ '๋๋ฉ์ธ ๋ก์ง'๊ณผ 'UI ๋ ๋๋ง'์ ๋ถ๋ฆฌํ๋ ๊ธฐ์ค์ ์ค๋ช ํฉ๋๋ค. ์ด๋ฅผ ํตํด UI ๋ณ๊ฒฝ ์์ด ๋ก์ง๋ง ๋ ๋ฆฝ์ ์ผ๋ก ๋จ์ ํ ์คํธ(Unit Test)๋ฅผ ๊ฐ๋ฅํ๊ฒ ํจ์ ๊ฐ์กฐํฉ๋๋ค."
- Level 3 (Specialist): "'Headless Component' ํจํด์ด๋ 'Hook ๊ธฐ๋ฐ ์ํคํ ์ฒ'๋ฅผ ์ธ๊ธํฉ๋๋ค. UI ํ๋ฆฌ์ ํ ์ด์ ๊ณผ ์ํ ๊ด๋ฆฌ ์์ง์ ์์ ํ ๊ฒฉ๋ฆฌํ์ฌ, ์น๋ฟ๋ง ์๋๋ผ ์ฑ(React Native) ๋ฑ ๋ค๋ฅธ ํ๋ซํผ์์๋ ๋์ผํ ๋น์ฆ๋์ค ๋ก์ง ํ ์ ๊ณต์ ํ ์ ์๋ ํ์ฅ์ฑ ์๋ ๊ตฌ์กฐ๋ฅผ ์ ์ํฉ๋๋ค."
Q2. useSyncExternalStore ํ ์ด ๋์ ๋ ๋ฐฐ๊ฒฝ๊ณผ, ํ ์ด๋ง(Tearing) ํ์์ ๋ฐฉ์งํ๋ ์๋ฆฌ๋ ๋ฌด์์ธ๊ฐ์?
๐ฏ ์ถ์ ์๋
React 18 ๋์์ฑ ๋ชจ๋์์ ๋ฐ์ํ ์ ์๋ ๋ฏธ๋ฌํ ์๊ฐ์ ๋ฒ๊ทธ๋ฅผ ์ดํดํ๊ณ , ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Redux, Zustand ๋ฑ)๊ฐ ๋ฆฌ์กํธ ์ค์ผ์ค๋ฌ์ ์ด๋ป๊ฒ ํ์ ํ๋์ง ๊น์ด ์๊ฒ ์๋์ง ํ์ธํฉ๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ window.innerWidth๋ฅผ ์ ์ญ ์ํ์ฒ๋ผ ์ฐ๊ธฐ ์ํด ๋จ์ํ useEffect๋ฅผ ์ผ๋ค๊ฐ ๋ ์ด์์์ด ์ฐข์ด์ง๋ ํ์์ ๋ฐ๊ฒฌํ์ต๋๋ค.
// ๐ฃ ์์ฒ : "๊ทธ๋ฅ useEffect๋ก ๊ฐ ๊ฐ์ํ๋ฉด ๋๋ ๊ฑฐ ์๋๊ฐ์?"
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width; // โ ๏ธ ๋์์ฑ ๋ชจ๋์์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ์๋ก ๋ค๋ฅธ width๋ฅผ ์ฝ์ ์ํ(Tearing) ์์
}๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋, ๋ฆฌ์กํธ 18์ ๋์์ฑ ๋ ๋๋ง์ ๋์ค์ ๋ฉ์ถ ์ ์์ด์. ๋ ๋๋ง 1๋จ๊ณ์์ A ์ปดํฌ๋ํธ๊ฐ width๋ฅผ ์ฝ๊ณ , ๊ทธ ์ฌ์ด์ ๋ฆฌ์ฌ์ด์ฆ๊ฐ ๋ฐ์ํ ๋ค 2๋จ๊ณ์์ B ์ปดํฌ๋ํธ๊ฐ ์ฝ์ผ๋ฉด ํ๋ฉด์ด ์ง์ง์ด๊ฐ ๋ฉ๋๋ค. ์ด๊ฑธ ๋ง์ผ๋ผ๊ณ ๋ง๋ ๊ฒuseSyncExternalStore์ ๋๋ค."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๊ฐ ์์ ํ ์ธ๋ถ ์ํ ๊ตฌ๋ ๋ฐฉ์์ ์ ์ํฉ๋๋ค.
// ๐ฆ ์ํธ: "์ธ๋ถ ์ํ๋ ๋ฆฌ์กํธ์ ๋ ๋๋ง ์๋์ ๋ง์ง ์์ ์ ์์ต๋๋ค. ๊ฐ์ ๋ก ๋๊ธฐํํ์ธ์."
const widthStore = {
subscribe: (cb) => {
window.addEventListener('resize', cb);
return () => window.removeEventListener('resize', cb);
},
getSnapshot: () => window.innerWidth,
};
function useWindowWidth() {
// โ
๋ฆฌ์กํธ์๊ฒ '์ด ๊ฐ์ ์ธ๋ถ์์ ์ค๋๊น ๋ ๋๋ง ์ค์ ๋ฐ๋๋ฉด ์ค๋จํด!'๋ผ๊ณ ์๋ ค์ค
return useSyncExternalStore(
widthStore.subscribe,
widthStore.getSnapshot
);
}๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "์ธ๋ถ ์ํ(Redux ๋ฑ)๋ฅผ ๋ฆฌ์กํธ์ ์ฐ๊ฒฐํด ์ฃผ๋ ํ ์ ๋๋ค. ๊ฐ์ด ๋ฐ๋๋ฉด ๋ฆฌ๋ ๋๋งํด ์ค๋๋ค."
- Level 2 (Senior): "๋์์ฑ ๋ ๋๋ง์ ์์
์ ์ชผ๊ฐ์ด ์ฒ๋ฆฌํ๋๋ฐ, ๊ทธ ์ฌ์ด ์ธ๋ถ ์ํ๊ฐ ๋ณํ๋ฉด ์๊ฐ์ ๋ถ์ผ์น(Tearing)๊ฐ ๋ฐ์ํจ์ ์ค๋ช
ํฉ๋๋ค.
useSyncExternalStore๋ ์ฝ๊ธฐ ์์ ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋์ ๋์์์ ์ธ๊ธํฉ๋๋ค." - Level 3 (Specialist): "์ด ํ ์ด ์์์ (Atomic) ์ ๋ฐ์ดํธ๋ฅผ ์ด๋ป๊ฒ ๋ณด์ฅํ๋์ง ๋ด๋ถ ๋ฉ์ปค๋์ฆ์ ์ค๋ช ํฉ๋๋ค. ๋ ๋๋ง ์ค ์ธ๋ถ ๊ฐ์ด ๋ณํ๋ฉด ๋ค์ ๋ ๋๋ง์ ์๋ํ๊ฑฐ๋ ๋๊ธฐ์ ์ ๋ฐ์ดํธ๋ก ์ ํํ์ฌ ์ฌ์ฉ์์๊ฒ ํญ์ ์ผ๊ด๋ ์ค๋ ์ท์ ๋ณด์ฌ์ฃผ๋ '์ผ๊ด์ฑ ๋ณด์ฅ' ์ ๋ต์ ๋ถ์ํฉ๋๋ค."
๐ ์ค์ ๋ณํ ์ง๋ฌธ (Related Variations)
Q182. ๊ณ ์ฐจ ์ปดํฌ๋ํธ(HOC) ํจํด๊ณผ ์ปค์คํ ํ ํจํด์ ์ฅ๋จ์ ์ ๋น๊ตํด ๋ณด์ธ์.
- ๐ฏ ์ถ์ ์๋: ๋ฆฌ์กํธ์ ๋ก์ง ์ฌ์ฌ์ฉ ํจํด ๋ณ์ฒ์ฌ๋ฅผ ์ดํดํ๊ณ , ์ํฉ์ ๋ง๋ ๊ฐ์ฅ ์ ์ ํ ๋๊ตฌ๋ฅผ ์ ํํ ์ ์๋์ง ํ์ธํฉ๋๋ค.
- ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ: ์ปค์คํ ํ ์ ํจ์ํ ์ปดํฌ๋ํธ์ ํ๋ฆ ์์์ ์ํ์ ๋ก์ง์ ๋งค์ฐ ์ ์ฐํ๊ฒ ์กฐํฉํ ์ ์์ด ํ์ฌ ๋ฆฌ์กํธ์ ํ์ค์ ๋๋ค. ๋ฐ๋ฉด, HOC๋ ์๋ณธ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ๋ ๊ตฌ์กฐ ํน์ฑ์ Props๊ฐ ์ด๋์ ์ค๋์ง ๋ถ๋ช ํํด์ง๋ 'Props Drilling'์ด๋ '์ด๋ฆ ์ถฉ๋' ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ์ต๋๋ค. ํ์ง๋ง ์ธ์ฆ ์ฒดํฌ๋ ๋ก๊น ์ฒ๋ผ UI ์์ฒด๋ฅผ ๊ฐ์ธ๊ฑฐ๋ ์ฃผ์ ํด์ผ ํ๋ ์๊ฐ์ ์ธ ํก๋จ ๊ด์ฌ์ฌ(Cross-cutting Concerns)์๋ ์ฌ์ ํ HOC๊ฐ ์ ์ธ์ ์ด๊ณ ๊น๋ํ ๋์์ด ๋ ์ ์์ต๋๋ค.
Q249. ๋ฆฌ์กํธ์์ ๋๋ฐ์ด์ค(Debounce)์ ์ฐ๋กํ(Throttle)์ ์ ์ฉํ ๋ ์ฃผ์ํ ์ ์ ๋ฌด์์ธ๊ฐ์?
- ๐ฏ ์ถ์ ์๋: ๋ฆฌ๋ ๋๋ง ์๋ง๋ค ํจ์๊ฐ ์๋ก ์์ฑ๋๋ ๋ฆฌ์กํธ์ ํน์ฑ๊ณผ ํ์ด๋จธ ๋ฉ์ปค๋์ฆ ๊ฐ์ ์ถฉ๋์ ๋ฐฉ์ดํ ์ ์๋์ง ํ์ธํฉ๋๋ค.
- ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ: ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ๋๋ง๋ค ์ ์๋ ํจ์๋ ์๋ก ์์ฑ๋ฉ๋๋ค. ๋จ์ํ๊ฒ
lodash.debounce๋ฅผ ํจ์ ์์ ์ ์ธํ๋ฉด ๋ฆฌ๋ ๋๋ง๋ง๋ค ์๋ก์ด ํ์ด๋จธ๊ฐ ์๊ฒจ ์ ๊ธฐ๋ฅ์ ๋ชป ํ๊ฒ ๋ฉ๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๋ ค๋ฉดuseMemo๋useCallback์ผ๋ก ๋๋ฐ์ด์ค๋ ํจ์ ์ธ์คํด์ค๋ฅผ ์ ์งํ๊ฑฐ๋,useRef๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋ง ์ฌ์ดํด๊ณผ ๋ฌด๊ดํ๊ฒ ํ์ด๋จธ ์ํ๋ฅผ ๋ณด์กดํด์ผ ํฉ๋๋ค. ๋ํ ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์ ๋ฐ๋์cancel์ ํธ์ถํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์์ ์์์น ๋ชปํ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๋ฐฉ์งํด์ผ ํฉ๋๋ค.
Q258. ๋ก์ปฌ ์คํ ๋ฆฌ์ง ๋๊ธฐํ ํ ์ ์ค๊ณํ ๋ SSR ํ๊ฒฝ์ 'window is not defined' ์๋ฌ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ๋์?
- ๐ฏ ์ถ์ ์๋: ์ ๋๋ฒ์ค(Universal) ์๋ฐ์คํฌ๋ฆฝํธ ์คํ ํ๊ฒฝ์ ๋ํ ์ดํด์ Next.js ๋ฑ SSR ํ๋ ์์ํฌ์์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ์ธํฉ๋๋ค.
- ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ: ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง ์์๋ ๋ธ๋ผ์ฐ์ ๊ฐ์ฒด์ธ
window๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์useState์ ์ด๊ธฐ๊ฐ์ผ๋ก ์คํ ๋ฆฌ์ง๋ฅผ ์ง์ ์ฝ์ผ๋ ค ํ๋ฉด ์๋ฌ๊ฐ ๋ฉ๋๋ค. ํด๊ฒฐ์ฑ ์ผ๋ก๋useEffect๋ด์์๋งwindow์ ์ ๊ทผํ์ฌ ๋ฐํ์์ ๊ฐ์ ์ค์ ํ๊ฑฐ๋,typeof window !== 'undefined'์กฐ๊ฑด๋ฌธ์ผ๋ก ๊ฐ๋ ๋ก์ง์ ์์ฑํด์ผ ํฉ๋๋ค. ๋ํ ์ต์ ๋ฆฌ์กํธ์์๋useSyncExternalStore์ ์ธ ๋ฒ์งธ ์ธ์์ธgetServerSnapshot์ ํ์ฉํ์ฌ ์๋ฒ์ฉ ๊ธฐ๋ณธ๊ฐ์ ๋ฐ๋ก ์ ๊ณตํจ์ผ๋ก์จ ํ์ด๋๋ ์ด์ ๋ถ์ผ์น(Hydration Mismatch)๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๐ฃ ์์ฒ ์ด์ ๋ณต๊ธฐ ์ผ๊ธฐ
์ค๋ 'ํ
์ด๋ง'์ด๋ผ๋ ๋ง์ ์ฒ์ ๋ค์๋๋ฐ, ํ๋ฉด์ด ์ฐข์ด์ง๋ค๋ ํํ์ด ๋๋ฌด ๋ฌด์ญ๊ฒ ๋ค๊ฐ์๋ค. ๊ทธ๋์ ๋ด๊ฐ ๋ง๋ ์ ์ญ ์ํ ๊ตฌ๋
๋ก์ง๋ค์ด ์ด ์ํ์ ๋
ธ์ถ๋์ด ์์๋ค๋... ๋ฆฌ์กํธ๊ฐ ์ useSyncExternalStore๋ผ๋ ๊ดด์ํ ์ด๋ฆ์ ํ
์ ๋ง๋ค์๋์ง ์ด์ ์ผ ์ดํด๊ฐ ๊ฐ๋ค.
๐ก "์ปดํฌ๋ํธ์์ ์ค์ํ ๊ฑด ๋ฌด์์ ๊ทธ๋ฆฌ๋๋๊ฐ ์๋๋ผ, ๋ฌด์์ ๊ทธ๋ฆฌ์ง ์๊ธฐ๋ก ๊ฒฐ์ ํ๋๋์ ์๋ค."
๋ด์ผ์ ์ํ ๊ด๋ฆฌ์ ์ ์ํฐ, 'Flux ์ํคํ ์ฒ์ ์ ์ญ ์ํ'๋ฅผ ๊ณต๋ถํ๋ค. Redux๋ถํฐ Zustand๊น์ง, ์ด ์๋ง์ ๋๊ตฌ๋ค ์ค์์ ์ฐ๋ฆฌ ์์๋ค ์ปค๋ฎค๋ํฐ์ ๋ฑ ๋ง๋ ์นผ์ ๊ณจ๋ผ๋ด์ผ์ง! โ๏ธ๐ก๏ธ