Reactμ experimental_useSyncExternalStore ν μ νμ©νμ¬ ν¨μ¨μ μ΄κ³ μ λ’°μ± λμ μΈλΆ μ€ν μ΄ κ΅¬λ κ΄λ¦¬λ₯Ό μν μ¬μΈ΅ κ°μ΄λμ λλ€. κΈλ‘λ² λͺ¨λ² μ¬λ‘μ μμ λ₯Ό ν¬ν¨ν©λλ€.
Reactμ experimental_useSyncExternalStoreλ‘ μ€ν μ΄ κ΅¬λ λ§μ€ν°νκΈ°
λμμμ΄ μ§ννλ μΉ κ°λ° νκ²½μμ μΈλΆ μνλ₯Ό ν¨μ¨μ μΌλ‘ κ΄λ¦¬νλ κ²μ λ§€μ° μ€μν©λλ€. Reactλ μ μΈμ νλ‘κ·Έλλ° ν¨λ¬λ€μμ ν΅ν΄ μ»΄ν¬λνΈ μνλ₯Ό μ²λ¦¬νλ κ°λ ₯ν λꡬλ₯Ό μ 곡ν©λλ€. κ·Έλ¬λ μ체μ μΈ κ΅¬λ μ μ μ§νλ μΈλΆ μν κ΄λ¦¬ μ루μ μ΄λ λΈλΌμ°μ API(μ: WebSocket, λΈλΌμ°μ μ€ν 리μ§, 컀μ€ν μ΄λ²€νΈ μλ―Έν°)μ ν΅ν©ν λ κ°λ°μλ€μ μ’ μ’ React μ»΄ν¬λνΈ νΈλ¦¬λ₯Ό λκΈ°ν μνλ‘ μ μ§νλ λ° λ³΅μ‘μ±μ κ²ͺμ΅λλ€. λ°λ‘ μ΄ μ§μ μμ experimental_useSyncExternalStore ν μ΄ λ±μ₯νμ¬ μ΄λ¬ν ꡬλ μ κ΄λ¦¬νκΈ° μν κ²¬κ³ νκ³ μ±λ₯μ΄ λ°μ΄λ μ루μ μ μ 곡ν©λλ€. μ΄ μ’ ν© κ°μ΄λμμλ κΈλ‘λ² μ¬μ©μλ₯Ό λμμΌλ‘ μ΄ ν μ 볡μ‘μ±, μ΄μ λ° μ€μ μ μ© μ¬λ‘λ₯Ό μμΈν μ΄ν΄λ³΄κ² μ΅λλ€.
μΈλΆ μ€ν μ΄ κ΅¬λ μ μ΄λ €μ
experimental_useSyncExternalStoreμ λν΄ μμ보기 μ μ, React μ ν리μΌμ΄μ
λ΄μμ μΈλΆ μ€ν μ΄λ₯Ό ꡬλ
ν λ κ°λ°μλ€μ΄ νν κ²ͺλ μ΄λ €μμ μ΄ν΄ν΄ λ΄
μλ€. μ ν΅μ μΌλ‘ μ΄λ λ€μκ³Ό κ°μ μμ
μ ν¬ν¨νμ΅λλ€:
- μλ ꡬλ
κ΄λ¦¬: κ°λ°μλ€μ λ©λͺ¨λ¦¬ λμλ₯Ό λ°©μ§νκ³ μ μ ν μν μ
λ°μ΄νΈλ₯Ό 보μ₯νκΈ° μν΄
useEffectμμ μλμΌλ‘ μ€ν μ΄λ₯Ό ꡬλ νκ³ μ 리 ν¨μμμ ꡬλ μ ν΄μ§ν΄μΌ νμ΅λλ€. μ΄ μ κ·Ό λ°©μμ μ€λ₯κ° λ°μνκΈ° μ½κ³ λ―Έλ¬ν λ²κ·Έλ‘ μ΄μ΄μ§ μ μμ΅λλ€. - λͺ¨λ λ³κ²½μ λν 리λ λλ§: μ μ€ν μ΅μ ν μμ΄λ μΈλΆ μ€ν μ΄μ μμ λ³κ²½ νλνλκ° μ 체 μ»΄ν¬λνΈ νΈλ¦¬μ 리λ λλ§μ μ λ°νμ¬ νΉν 볡μ‘ν μ ν리μΌμ΄μ μμ μ±λ₯ μ νλ₯Ό μ΄λν μ μμ΅λλ€.
- λμμ± λ¬Έμ : λ¨μΌ μ¬μ©μ μνΈμμ© λμ μ»΄ν¬λνΈκ° μ¬λ¬ λ² λ λλ§ λ° λ¦¬λ λλ§λ μ μλ λμμ± React(Concurrent React)μ λ§₯λ½μμ λΉλκΈ° μ λ°μ΄νΈλ₯Ό κ΄λ¦¬νκ³ μ€λλ λ°μ΄ν°(stale data)λ₯Ό λ°©μ§νλ κ²μ ν¨μ¬ λ μ΄λ €μμ§ μ μμ΅λλ€. ꡬλ μ΄ μ λ°νκ² μ²λ¦¬λμ§ μμΌλ©΄ κ²½μ μν(Race conditions)κ° λ°μν μ μμ΅λλ€.
- κ°λ°μ κ²½ν: ꡬλ κ΄λ¦¬μ νμν μμ©κ΅¬ μ½λκ° μ»΄ν¬λνΈ λ‘μ§μ 볡μ‘νκ² λ§λ€μ΄ κ°λ μ±κ³Ό μ μ§λ³΄μμ±μ λ¨μ΄λ¨λ¦΄ μ μμ΅λλ€.
μ€μκ° μ¬κ³ μ λ°μ΄νΈ μλΉμ€λ₯Ό μ¬μ©νλ κΈλ‘λ² μ΄μ»€λ¨Έμ€ νλ«νΌμ μκ°ν΄ λ΄ μλ€. μ¬μ©μκ° μ νμ λ³Ό λ ν΄λΉ μ»΄ν¬λνΈλ νΉμ μ νμ μ¬κ³ μ λ°μ΄νΈλ₯Ό ꡬλ ν΄μΌ ν©λλ€. μ΄ κ΅¬λ μ΄ μ¬λ°λ₯΄κ² κ΄λ¦¬λμ§ μμΌλ©΄ μ€λλ μ¬κ³ μκ° νμλμ΄ μ¬μ©μ κ²½νμ μ νμν¬ μ μμ΅λλ€. λν μ¬λ¬ μ¬μ©μκ° λμΌν μ νμ λ³΄κ³ μλ κ²½μ° λΉν¨μ¨μ μΈ κ΅¬λ μ²λ¦¬λ μλ² λ¦¬μμ€λ₯Ό μλ°νκ³ μ¬λ¬ μ§μμ κ±Έμ³ μ ν리μΌμ΄μ μ±λ₯μ μν₯μ λ―ΈμΉ μ μμ΅λλ€.
experimental_useSyncExternalStore μκ°
Reactμ experimental_useSyncExternalStore ν
μ Reactμ λ΄λΆ μν κ΄λ¦¬μ μΈλΆ ꡬλ
κΈ°λ° μ€ν μ΄ κ°μ 격차λ₯Ό ν΄μνκΈ° μν΄ μ€κ³λμμ΅λλ€. μ΄ ν
μ νΉν λμμ± React(Concurrent React)μ λ§₯λ½μμ μ΄λ¬ν μ€ν μ΄λ₯Ό ꡬλ
νλ λ μ λ’°μ± μκ³ ν¨μ¨μ μΈ λ°©λ²μ μ 곡νκΈ° μν΄ λμ
λμμ΅λλ€. μ΄ ν
μ ꡬλ
κ΄λ¦¬μ 볡μ‘μ±μ μλΉ λΆλΆ μΆμννμ¬ κ°λ°μκ° μ ν리μΌμ΄μ
μ ν΅μ¬ λ‘μ§μ μ§μ€ν μ μλλ‘ ν©λλ€.
ν μ μκ·Έλμ²λ λ€μκ³Ό κ°μ΅λλ€:
const state = experimental_useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
κ° λ§€κ°λ³μλ₯Ό λΆμν΄ λ³΄κ² μ΅λλ€:
subscribe:callbackμ μΈμλ‘ λ°μ μΈλΆ μ€ν μ΄μ ꡬλ νλ ν¨μμ λλ€. μ€ν μ΄μ μνκ° λ³κ²½λ λλ§λ€callbackμ΄ νΈμΆλμ΄μΌ ν©λλ€. μ΄ ν¨μλ λν μ»΄ν¬λνΈκ° λ§μ΄νΈ ν΄μ λκ±°λ ꡬλ μ λ€μ μ€μ ν΄μΌ ν λ νΈμΆλunsubscribeν¨μλ₯Ό λ°νν΄μΌ ν©λλ€.getSnapshot: μΈλΆ μ€ν μ΄μ νμ¬ κ°μ λ°ννλ ν¨μμ λλ€. Reactλ λ λλ§ν μ΅μ μνλ₯Ό μ»κΈ° μν΄ μ΄ ν¨μλ₯Ό νΈμΆν©λλ€.getServerSnapshot(μ ν μ¬ν): μ΄ ν¨μλ μλ²μμ μ€ν μ΄ μνμ μ΄κΈ° μ€λ μ·μ μ 곡ν©λλ€. μ΄λ μλ² μ¬μ΄λ λ λλ§(SSR)κ³Ό νμ΄λλ μ΄μ (hydration)μ λ§€μ° μ€μνλ©°, ν΄λΌμ΄μΈνΈ μΈ‘μ΄ μλ²μ μΌκ΄λ λ·°λ₯Ό λ λλ§νλλ‘ λ³΄μ₯ν©λλ€. μ΄ ν¨μκ° μ 곡λμ§ μμΌλ©΄ ν΄λΌμ΄μΈνΈλ μ΄κΈ° μνκ° μλ²μ λμΌνλ€κ³ κ°μ νκ² λλ©°, μ΄λ μ μ€νκ² μ²λ¦¬νμ§ μμ κ²½μ° νμ΄λλ μ΄μ λΆμΌμΉλ‘ μ΄μ΄μ§ μ μμ΅λλ€.
λ΄λΆ λμ λ°©μ
experimental_useSyncExternalStoreλ κ³ μ±λ₯μΌλ‘ μ€κ³λμμ΅λλ€. λ€μκ³Ό κ°μ λ°©λ²μΌλ‘ 리λ λλ§μ μ§λ₯μ μΌλ‘ κ΄λ¦¬ν©λλ€:
- μ λ°μ΄νΈ μΌκ΄ μ²λ¦¬: μ°μμ μΌλ‘ λ°μνλ μ¬λ¬ μ€ν μ΄ μ λ°μ΄νΈλ₯Ό μΌκ΄ μ²λ¦¬νμ¬ λΆνμν 리λ λλ§μ λ°©μ§ν©λλ€.
- μ€λλ λ°μ΄ν° μ½κΈ° λ°©μ§: λμμ± λͺ¨λμμ Reactκ° μ½λ μνκ° νμ μ΅μ μνμμ 보μ₯νμ¬, μ¬λ¬ λ λλ§μ΄ λμμ λ°μνλλΌλ μ€λλ λ°μ΄ν°λ‘ λ λλ§λλ κ²μ λ°©μ§ν©λλ€.
- μ΅μ νλ ꡬλ ν΄μ§: ꡬλ ν΄μ§ νλ‘μΈμ€λ₯Ό μ λ’°μ± μκ² μ²λ¦¬νμ¬ λ©λͺ¨λ¦¬ λμλ₯Ό λ°©μ§ν©λλ€.
μ΄λ¬ν 보μ₯μ μ 곡ν¨μΌλ‘μ¨ experimental_useSyncExternalStoreλ κ°λ°μμ μμ
μ ν¬κ² λ¨μννκ³ μΈλΆ μνμ μμ‘΄νλ μ ν리μΌμ΄μ
μ μ λ°μ μΈ μμ μ±κ³Ό μ±λ₯μ ν₯μμν΅λλ€.
experimental_useSyncExternalStore μ¬μ©μ μ΄μ
experimental_useSyncExternalStoreλ₯Ό μ±ννλ©΄ λ€μκ³Ό κ°μ μ¬λ¬ κ°μ§ κ°λ ₯ν μ΄μ μ΄ μμ΅λλ€:
1. μ±λ₯ λ° ν¨μ¨μ± ν₯μ
μ
λ°μ΄νΈ μΌκ΄ μ²λ¦¬ λ° μ€λλ λ°μ΄ν° μ½κΈ° λ°©μ§μ κ°μ ν
μ λ΄λΆ μ΅μ νλ λ λΉ λ₯Έ μ¬μ©μ κ²½νμΌλ‘ μ§μ μ΄μ΄μ§λλ€. λ€μν λ€νΈμν¬ μ‘°κ±΄κ³Ό κΈ°κΈ° μ±λ₯μ κ°μ§ μ¬μ©μκ° μλ κΈλ‘λ² μ ν리μΌμ΄μ
μ κ²½μ°, μ΄λ¬ν μ±λ₯ ν₯μμ λ§€μ° μ€μν©λλ€. μλ₯Ό λ€μ΄, λμΏ, λ°λ, λ΄μμ νΈλ μ΄λκ° μ¬μ©νλ κΈμ΅ κ±°λ μ ν리μΌμ΄μ
μ μ΅μνμ μ§μ° μκ°μΌλ‘ μ€μκ° μμ₯ λ°μ΄ν°λ₯Ό νμν΄μΌ ν©λλ€. experimental_useSyncExternalStoreλ νμν 리λ λλ§λ§ λ°μνλλ‘ λ³΄μ₯νμ¬ λ°μ΄ν° νλ¦μ΄ λ§μ μν©μμλ μ ν리μΌμ΄μ
μ λ°μμ±μ μ μ§ν©λλ€.
2. μ λ’°μ± ν₯μ λ° λ²κ·Έ κ°μ
μλ ꡬλ
κ΄λ¦¬λ νΉν λ©λͺ¨λ¦¬ λμμ κ²½μ μνμ κ°μ λ²κ·Έμ μΌλ°μ μΈ μμΈμ
λλ€. experimental_useSyncExternalStoreλ μ΄ λ‘μ§μ μΆμννμ¬ μΈλΆ ꡬλ
μ κ΄λ¦¬νλ λ μ λ’°μ± μκ³ μμΈ‘ κ°λ₯ν λ°©λ²μ μ 곡ν©λλ€. μ΄λ μ¬κ°ν μ€λ₯μ κ°λ₯μ±μ μ€μ¬ λ μμ μ μΈ μ ν리μΌμ΄μ
μ λ§λλλ€. μ€μκ° νμ λͺ¨λν°λ§ λ°μ΄ν°μ μμ‘΄νλ ν¬μ€μΌμ΄ μ ν리μΌμ΄μ
μ μμν΄ λ³΄μμμ€. λ°μ΄ν° νμμ λΆμ νμ±μ΄λ μ§μ°μ μ¬κ°ν κ²°κ³Όλ₯Ό μ΄λν μ μμ΅λλ€. μ΄ ν
μ΄ μ 곡νλ μ λ’°μ±μ μ΄λ¬ν μλ리μ€μμ λ§€μ° μ€μν©λλ€.
3. λμμ± React(Concurrent React)μμ μνν ν΅ν©
λμμ± Reactλ 볡μ‘ν λ λλ§ λμμ λμ
ν©λλ€. experimental_useSyncExternalStoreλ λμμ±μ μΌλμ λκ³ λ§λ€μ΄μ Έ Reactκ° μ€λ¨ κ°λ₯ν λ λλ§μ μνν λμλ μΈλΆ μ€ν μ΄ κ΅¬λ
μ΄ μ¬λ°λ₯΄κ² λμνλλ‘ λ³΄μ₯ν©λλ€. μ΄λ λ©μΆ€ νμ μμ΄ λ³΅μ‘ν μ¬μ©μ μνΈμμ©μ μ²λ¦¬ν μ μλ νλμ μ΄κ³ λ°μμ±μ΄ λ°μ΄λ React μ ν리μΌμ΄μ
μ ꡬμΆνλ λ° λ§€μ° μ€μν©λλ€.
4. κ°λ°μ κ²½ν λ¨μν
ꡬλ λ‘μ§μ μΊ‘μνν¨μΌλ‘μ¨ μ΄ ν μ κ°λ°μκ° μμ±ν΄μΌ νλ μμ©κ΅¬ μ½λλ₯Ό μ€μ¬μ€λλ€. μ΄λ λ κΉ¨λνκ³ μ μ§λ³΄μνκΈ° μ¬μ΄ μ»΄ν¬λνΈ μ½λλ‘ μ΄μ΄μ§λ©° μ λ°μ μΈ κ°λ°μ κ²½νμ ν₯μμν΅λλ€. κ°λ°μλ ꡬλ λ¬Έμ λ₯Ό λλ²κΉ νλ λ° μκ°μ λ λ€μ΄κ³ κΈ°λ₯ κ°λ°μ λ λ§μ μκ°μ ν μ ν μ μμ΅λλ€.
5. μλ² μ¬μ΄λ λ λλ§(SSR) μ§μ
μ νμ λ§€κ°λ³μμΈ getServerSnapshotμ SSRμ νμμ μ
λλ€. μ΄λ₯Ό ν΅ν΄ μλ²μμ μΈλΆ μ€ν μ΄μ μ΄κΈ° μνλ₯Ό μ 곡ν μ μμ΅λλ€. μ΄λ μλ²μμ λ λλ§λ HTMLμ΄ νμ΄λλ μ΄μ
ν ν΄λΌμ΄μΈνΈ μΈ‘ React μ ν리μΌμ΄μ
μ΄ λ λλ§ν λ΄μ©κ³Ό μΌμΉνλλ‘ λ³΄μ₯νμ¬ νμ΄λλ μ΄μ
λΆμΌμΉλ₯Ό λ°©μ§νκ³ μ¬μ©μκ° μ½ν
μΈ λ₯Ό λ 빨리 λ³Ό μ μκ² ν¨μΌλ‘μ¨ μ²΄κ° μ±λ₯μ ν₯μμν΅λλ€.
μ€μ©μ μΈ μμ λ° μ¬μ© μ¬λ‘
experimental_useSyncExternalStoreλ₯Ό ν¨κ³Όμ μΌλ‘ μ μ©ν μ μλ λͺ κ°μ§ μΌλ°μ μΈ μλ리μ€λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
1. 컀μ€ν κΈλ‘λ² μ€ν μ΄μ ν΅ν©
λ§μ μ ν리μΌμ΄μ μ Zustand, Jotai λλ Valtioμ κ°μ 컀μ€ν μν κ΄λ¦¬ μ루μ μ΄λ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν©λλ€. μ΄λ¬ν λΌμ΄λΈλ¬λ¦¬λ μ’ μ’ `subscribe` λ©μλλ₯Ό λ ΈμΆν©λλ€. λ€μμ ν΅ν© λ°©λ²μ μμμ λλ€:
κ°λ¨ν μ€ν μ΄κ° μλ€κ³ κ°μ ν΄ λ΄ μλ€:
// simpleStore.js
let state = { count: 0 };
const listeners = new Set();
export const subscribe = (callback) => {
listeners.add(callback);
return () => {
listeners.delete(callback);
};
};
export const getSnapshot = () => state;
export const increment = () => {
state = { count: state.count + 1 };
listeners.forEach(callback => callback());
};
React μ»΄ν¬λνΈμμ:
import React, { experimental_useSyncExternalStore } from 'react';
import { subscribe, getSnapshot, increment } from './simpleStore';
function Counter() {
const count = experimental_useSyncExternalStore(subscribe, getSnapshot);
return (
Count: {count}
);
}
μ΄ μλ κΉλν ν΅ν©μ 보μ¬μ€λλ€. subscribe ν¨μκ° μ§μ μ λ¬λκ³ getSnapshotμ΄ νμ¬ μνλ₯Ό κ°μ Έμ΅λλ€. experimental_useSyncExternalStoreλ ꡬλ
μ μλͺ
μ£ΌκΈ°λ₯Ό μλμΌλ‘ μ²λ¦¬ν©λλ€.
2. λΈλΌμ°μ API μμ (μ: LocalStorage, SessionStorage)
localStorageμ sessionStorageλ λκΈ°μ μ΄μ§λ§, μ¬λ¬ νμ΄λ μ°½μ΄ κ΄λ ¨λ μ€μκ° μ
λ°μ΄νΈλ₯Ό κ΄λ¦¬νκΈ°λ μ΄λ €μΈ μ μμ΅λλ€. storage μ΄λ²€νΈλ₯Ό μ¬μ©νμ¬ κ΅¬λ
μ μμ±ν μ μμ΅λλ€.
localStorageλ₯Ό μν ν¬νΌ ν
μ λ§λ€μ΄ λ΄
μλ€:
// useLocalStorage.js
import { experimental_useSyncExternalStore, useCallback } from 'react';
function subscribeToLocalStorage(key, callback) {
const handleStorageChange = (event) => {
if (event.key === key) {
callback(event.newValue);
}
};
window.addEventListener('storage', handleStorageChange);
// μ΄κΈ°κ°
const initialValue = localStorage.getItem(key);
callback(initialValue);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}
function getLocalStorageSnapshot(key) {
return localStorage.getItem(key);
}
export function useLocalStorage(key) {
const subscribe = useCallback(
(callback) => subscribeToLocalStorage(key, callback),
[key]
);
const getSnapshot = useCallback(() => getLocalStorageSnapshot(key), [key]);
return experimental_useSyncExternalStore(subscribe, getSnapshot);
}
μ»΄ν¬λνΈμμ:
import React from 'react';
import { useLocalStorage } from './useLocalStorage';
function SettingsPanel() {
const theme = useLocalStorage('appTheme'); // μ: 'light' λλ 'dark'
// useSyncExternalStoreλ₯Ό μ¬μ©νμ§ μλ μΈν° ν¨μλ νμν©λλ€
return (
Current theme: {theme || 'default'}
{/* ν
λ§ λ³κ²½ 컨νΈλ‘€μ localStorage.setItem()μ νΈμΆν©λλ€ */}
);
}
μ΄ ν¨ν΄μ μΉ μ ν리μΌμ΄μ μ μ¬λ¬ ν κ°μ μ€μ μ΄λ μ¬μ©μ κΈ°λ³Έ μ€μ μ λκΈ°ννλ λ° μ μ©νλ©°, νΉν μ¬λ¬ μ± μΈμ€ν΄μ€λ₯Ό μ΄μ΄ λ μ μλ κ΅μ μ¬μ©μμκ² μ μ©ν©λλ€.
3. μ€μκ° λ°μ΄ν° νΌλ (WebSocket, μλ²-μ μ‘ μ΄λ²€νΈ)
μ±ν
μ ν리μΌμ΄μ
, λΌμ΄λΈ λμ보λ λλ κ±°λ νλ«νΌκ³Ό κ°μ΄ μ€μκ° λ°μ΄ν° μ€νΈλ¦Όμ μμ‘΄νλ μ ν리μΌμ΄μ
μ κ²½μ° experimental_useSyncExternalStoreλ μμ°μ€λ¬μ΄ μ νμ
λλ€.
WebSocket μ°κ²°μ κ³ λ €ν΄ λ΄ μλ€:
// WebSocketService.js
let socket;
let currentData = null;
const listeners = new Set();
export const connect = (url) => {
socket = new WebSocket(url);
socket.onopen = () => {
console.log('WebSocket connected');
};
socket.onmessage = (event) => {
currentData = JSON.parse(event.data);
listeners.forEach(callback => callback(currentData));
};
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
socket.onclose = () => {
console.log('WebSocket disconnected');
};
};
export const subscribeToWebSocket = (callback) => {
listeners.add(callback);
// λ°μ΄ν°κ° μ΄λ―Έ μ¬μ© κ°λ₯νλ€λ©΄ μ¦μ νΈμΆ
if (currentData) {
callback(currentData);
}
return () => {
listeners.delete(callback);
// ꡬλ
μκ° λ μ΄μ μμΌλ©΄ μ νμ μΌλ‘ μ°κ²° ν΄μ
if (listeners.size === 0) {
// socket.close(); // μ°κ²° ν΄μ μ λ΅ κ²°μ
}
};
};
export const getWebSocketSnapshot = () => currentData;
export const sendMessage = (message) => {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(message);
}
};
React μ»΄ν¬λνΈμμ:
import React, { useEffect } from 'react';
import { experimental_useSyncExternalStore } from 'react';
import { connect, subscribeToWebSocket, getWebSocketSnapshot, sendMessage } from './WebSocketService';
const WEBSOCKET_URL = 'wss://global-data-feed.example.com'; // μμ κΈλ‘λ² URL
function LiveDataFeed() {
const data = experimental_useSyncExternalStore(
subscribeToWebSocket,
getWebSocketSnapshot
);
useEffect(() => {
connect(WEBSOCKET_URL);
}, []);
const handleSend = () => {
sendMessage('Hello Server!');
};
return (
Live Data
{data ? (
{JSON.stringify(data, null, 2)}
) : (
Loading data...
)}
);
}
μ΄ ν¨ν΄μ λΌμ΄λΈ μ€ν¬μΈ μ μ, μ£Όμ μμΈ, λλ νμ νΈμ§ λꡬμ κ°μ΄ μ€μκ° μ λ°μ΄νΈκ° μμλλ κΈλ‘λ² κ³ κ°μ λμμΌλ‘ νλ μ ν리μΌμ΄μ μ λ§€μ° μ€μν©λλ€. μ΄ ν μ νμλλ λ°μ΄ν°κ° νμ μ΅μ μνμ΄κ³ λ€νΈμν¬ λ³λ μ€μλ μ ν리μΌμ΄μ μ΄ λ°μμ±μ μ μ§νλλ‘ λ³΄μ₯ν©λλ€.
4. μλνν° λΌμ΄λΈλ¬λ¦¬μμ ν΅ν©
λ§μ μλνν° λΌμ΄λΈλ¬λ¦¬λ μ체 λ΄λΆ μνλ₯Ό κ΄λ¦¬νκ³ κ΅¬λ
APIλ₯Ό μ 곡ν©λλ€. experimental_useSyncExternalStoreλ μνν ν΅ν©μ κ°λ₯νκ² ν©λλ€:
- μ§λ¦¬ μμΉ API: μμΉ λ³κ²½ ꡬλ .
- μ κ·Όμ± λꡬ: μ¬μ©μ κΈ°λ³Έ μ€μ λ³κ²½(μ: κΈκΌ΄ ν¬κΈ°, λλΉ μ€μ ) ꡬλ .
- μ°¨νΈ λΌμ΄λΈλ¬λ¦¬: μ°¨νΈ λΌμ΄λΈλ¬λ¦¬μ λ΄λΆ λ°μ΄ν° μ€ν μ΄μμ μ€μκ° λ°μ΄ν° μ λ°μ΄νΈμ λ°μ.
ν΅μ¬μ λΌμ΄λΈλ¬λ¦¬μ subscribe λ° getSnapshot(λλ λλ±ν) λ©μλλ₯Ό μλ³νκ³ μ΄λ₯Ό experimental_useSyncExternalStoreμ μ λ¬νλ κ²μ
λλ€.
μλ² μ¬μ΄λ λ λλ§(SSR) λ° νμ΄λλ μ΄μ
SSRμ νμ©νλ μ ν리μΌμ΄μ
μ κ²½μ°, μλ²μμ μνλ₯Ό μ¬λ°λ₯΄κ² μ΄κΈ°ννλ κ²μ ν΄λΌμ΄μΈνΈ μΈ‘ 리λ λλ§ λ° νμ΄λλ μ΄μ
λΆμΌμΉλ₯Ό νΌνλ λ° μ€μν©λλ€. experimental_useSyncExternalStoreμ getServerSnapshot λ§€κ°λ³μλ μ΄ λͺ©μ μ μν΄ μ€κ³λμμ΅λλ€.
컀μ€ν μ€ν μ΄ μμ λ‘ λμκ° SSR μ§μμ μΆκ°ν΄ λ΄ μλ€:
// simpleStore.js (SSR ν¬ν¨)
let state = { count: 0 };
const listeners = new Set();
export const subscribe = (callback) => {
listeners.add(callback);
return () => {
listeners.delete(callback);
};
};
export const getSnapshot = () => state;
// μ΄ ν¨μλ μλ²μμ μ΄κΈ° μνλ₯Ό κ°μ Έμ€κΈ° μν΄ νΈμΆλ©λλ€
export const getServerSnapshot = () => {
// μ€μ SSR μλ리μ€μμλ μλ² λ λλ§ μ»¨ν
μ€νΈμμ μνλ₯Ό κ°μ Έμ΅λλ€
// μμ°μ μν΄ μ΄κΈ° ν΄λΌμ΄μΈνΈ μνμ λμΌνλ€κ³ κ°μ ν©λλ€
return { count: 0 };
};
export const increment = () => {
state = { count: state.count + 1 };
listeners.forEach(callback => callback());
};
React μ»΄ν¬λνΈμμ:
import React, { experimental_useSyncExternalStore } from 'react';
import { subscribe, getSnapshot, getServerSnapshot, increment } from './simpleStore';
function Counter() {
// SSRμ μν΄ getServerSnapshot μ λ¬
const count = experimental_useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
return (
Count: {count}
);
}
μλ²μμ Reactλ getServerSnapshotμ νΈμΆνμ¬ μ΄κΈ° κ°μ μ»μ΅λλ€. ν΄λΌμ΄μΈνΈμμ νμ΄λλ μ΄μ
νλ λμ Reactλ μλ²μμ λ λλ§λ HTMLμ ν΄λΌμ΄μΈνΈ μΈ‘ λ λλ§ μΆλ ₯κ³Ό λΉκ΅ν©λλ€. getServerSnapshotμ΄ μ νν μ΄κΈ° μνλ₯Ό μ 곡νλ©΄ νμ΄λλ μ΄μ
νλ‘μΈμ€κ° μννκ² μ§νλ©λλ€. μ΄λ μλ² λ λλ§μ΄ μ§λ¦¬μ μΌλ‘ λΆμ°λ μ μλ κΈλ‘λ² μ ν리μΌμ΄μ
μμ νΉν μ€μν©λλ€.
SSR λ° `getServerSnapshot`μ κ³Όμ
- λΉλκΈ° λ°μ΄ν° κ°μ Έμ€κΈ°: μΈλΆ μ€ν μ΄μ μ΄κΈ° μνκ° λΉλκΈ° μμ
(μ: μλ²μμμ API νΈμΆ)μ μμ‘΄νλ κ²½μ°,
experimental_useSyncExternalStoreλ₯Ό μ¬μ©νλ μ»΄ν¬λνΈλ₯Ό λ λλ§νκΈ° μ μ μ΄λ¬ν μμ μ΄ μλ£λλλ‘ ν΄μΌ ν©λλ€. Next.jsμ κ°μ νλ μμν¬λ μ΄λ₯Ό μ²λ¦¬νλ λ©μ»€λμ¦μ μ 곡ν©λλ€. - μΌκ΄μ±:
getServerSnapshotμ΄ λ°ννλ μνλ νμ΄λλ μ΄μ μ§ν ν΄λΌμ΄μΈνΈμμ μ¬μ©ν μ μλ μνμ *λ°λμ* μΌμΉν΄μΌ ν©λλ€. λΆμΌμΉκ° λ°μνλ©΄ νμ΄λλ μ΄μ μ€λ₯κ° λ°μν μ μμ΅λλ€.
κΈλ‘λ² μ¬μ©μλ₯Ό μν κ³ λ € μ¬ν
κΈλ‘λ² μ¬μ©μλ₯Ό μν μ ν리μΌμ΄μ μ ꡬμΆν λ μΈλΆ μν λ° κ΅¬λ κ΄λ¦¬λ μ μ€ν κ³ λ €κ° νμν©λλ€:
- λ€νΈμν¬ μ§μ° μκ°: λ€λ₯Έ μ§μμ μ¬μ©μλ λ€μν λ€νΈμν¬ μλλ₯Ό κ²½ννκ² λ©λλ€.
experimental_useSyncExternalStoreκ° μ 곡νλ μ±λ₯ μ΅μ νλ μ΄λ¬ν μλ리μ€μμ λμ± μ€μν©λλ€. - μκ°λ λ° μ€μκ° λ°μ΄ν°: μκ° λ―Όκ°μ± λ°μ΄ν°(μ: μ΄λ²€νΈ μΌμ , μ€μκ° μ μ)λ₯Ό νμνλ μ ν리μΌμ΄μ
μ μκ°λλ₯Ό μ¬λ°λ₯΄κ² μ²λ¦¬ν΄μΌ ν©λλ€.
experimental_useSyncExternalStoreλ λ°μ΄ν° λκΈ°νμ μ€μ μ λμ§λ§, λ°μ΄ν° μ체λ μΈλΆ μ μ₯μμ μ μ₯λκΈ° μ μ μκ°λλ₯Ό μΈμν΄μΌ ν©λλ€. - κ΅μ ν(i18n) λ° νμ§ν(l10n): μΈμ΄, ν΅ν λλ μ§μ νμμ λν μ¬μ©μ κΈ°λ³Έ μ€μ μ μΈλΆ μ μ₯μμ μ μ₯λ μ μμ΅λλ€. μ΄λ¬ν κΈ°λ³Έ μ€μ μ΄ μ ν리μΌμ΄μ μ λ€λ₯Έ μΈμ€ν΄μ€ κ°μ μμ μ μΌλ‘ λκΈ°νλλλ‘ νλ κ²μ΄ μ€μν©λλ€.
- μλ² μΈνλΌ: SSR λ° μ€μκ° κΈ°λ₯μ κ²½μ°, μ§μ° μκ°μ μ΅μννκΈ° μν΄ μ¬μ©μ κΈ°λ°μ λ κ°κΉμ΄ κ³³μ μλ²λ₯Ό λ°°ν¬νλ κ²μ κ³ λ €νμμμ€.
experimental_useSyncExternalStoreλ μ¬μ©μμ μμΉλ λ€νΈμν¬ μνμ κ΄κ³μμ΄ React μ ν리μΌμ΄μ
μ΄ μΈλΆ λ°μ΄ν° μμ€μ μ΅μ μνλ₯Ό μΌκ΄λκ² λ°μνλλ‘ λ³΄μ₯ν¨μΌλ‘μ¨ λμμ΄ λ©λλ€.
experimental_useSyncExternalStoreλ₯Ό μ¬μ©νμ§ λ§μμΌ ν κ²½μ°
κ°λ ₯νμ§λ§ experimental_useSyncExternalStoreλ νΉμ λͺ©μ μ μν΄ μ€κ³λμμ΅λλ€. μΌλ°μ μΌλ‘ λ€μκ³Ό κ°μ κ²½μ°μλ μ¬μ©νμ§ μμ΅λλ€:
- λ‘컬 μ»΄ν¬λνΈ μν κ΄λ¦¬: λ¨μΌ μ»΄ν¬λνΈ λ΄μ κ°λ¨ν μνμ κ²½μ° Reactμ λ΄μ₯
useStateλλuseReducerν μ΄ λ μ μ νκ³ κ°λ¨ν©λλ€. - λ¨μ λ°μ΄ν°λ₯Ό μν μ μ μν κ΄λ¦¬: μ μ μνκ° λΉκ΅μ μ μ μ΄κ³ 볡μ‘ν ꡬλ ν¨ν΄μ ν¬ν¨νμ§ μλ κ²½μ° React Contextλ κΈ°λ³Έμ μΈ μ μ μ€ν μ΄μ κ°μ λ κ°λ²Όμ΄ μ루μ μΌλ‘ μΆ©λΆν μ μμ΅λλ€.
- μ€μ μ μ₯μ μμ΄ λΈλΌμ°μ κ° λκΈ°ν: `storage` μ΄λ²€νΈ μμ λ ν κ° λκΈ°νλ₯Ό 보μ¬μ£Όμ§λ§ λΈλΌμ°μ λ©μ»€λμ¦μ μμ‘΄ν©λλ€. μ§μ ν κ΅μ°¨ κΈ°κΈ° λλ κ΅μ°¨ μ¬μ©μ λκΈ°νλ₯Ό μν΄μλ μ¬μ ν λ°±μλ μλ²κ° νμν©λλ€.
experimental_useSyncExternalStoreμ λ―Έλμ μμ μ±
experimental_useSyncExternalStoreλ νμ¬ 'μ€νμ (experimental)'μΌλ‘ νμλμ΄ μμμ κΈ°μ΅νλ κ²μ΄ μ€μν©λλ€. μ΄λ Reactμ μμ μ μΈ μΌλΆκ° λκΈ° μ μ APIκ° λ³κ²½λ μ μμμ μλ―Έν©λλ€. κ²¬κ³ ν μ루μ
μΌλ‘ μ€κ³λμμ§λ§, κ°λ°μλ μ΄ μ€νμ μνλ₯Ό μΈμ§νκ³ ν₯ν React λ²μ μμ λ°μν μ μλ API λ³κ²½μ λλΉν΄μΌ ν©λλ€. React νμ μ΄λ¬ν λμμ± κΈ°λ₯μ κ°μ νκΈ° μν΄ μ κ·Ήμ μΌλ‘ λ
Έλ ₯νκ³ μμΌλ©°, μ΄ ν
μ΄λ μ μ¬ν μΆμνκ° λ―Έλμ Reactμ μμ μ μΈ μΌλΆκ° λ κ°λ₯μ±μ΄ λ§€μ° λμ΅λλ€. 곡μ React λ¬Έμλ₯Ό μ΅μ μνλ‘ μ μ§νλ κ²μ΄ μ’μ΅λλ€.
κ²°λ‘
experimental_useSyncExternalStoreλ Reactμ ν
μνκ³μ μ€μν μΆκ° κΈ°λ₯μΌλ‘, μΈλΆ λ°μ΄ν° μμ€μ λν ꡬλ
μ κ΄λ¦¬νλ νμ€νλκ³ μ±λ₯μ΄ λ°μ΄λ λ°©λ²μ μ 곡ν©λλ€. μλ ꡬλ
κ΄λ¦¬μ 볡μ‘μ±μ μΆμννκ³ , SSRμ μ§μνλ©°, λμμ± Reactμ μννκ² μλν¨μΌλ‘μ¨ κ°λ°μκ° λ κ²¬κ³ νκ³ ν¨μ¨μ μ΄λ©° μ μ§λ³΄μνκΈ° μ¬μ΄ μ ν리μΌμ΄μ
μ ꡬμΆν μ μλλ‘ μ§μν©λλ€. μ€μκ° λ°μ΄ν°μ μμ‘΄νκ±°λ μΈλΆ μν λ©μ»€λμ¦κ³Ό ν΅ν©νλ λͺ¨λ κΈλ‘λ² μ ν리μΌμ΄μ
μ κ²½μ°, μ΄ ν
μ μ΄ν΄νκ³ νμ©νλ©΄ μ±λ₯, μ λ’°μ± λ° κ°λ°μ κ²½νμ ν¬κ² ν₯μμν¬ μ μμ΅λλ€. λ€μν κ΅μ μ¬μ©μλ₯Ό μν΄ κ΅¬μΆν λ μν κ΄λ¦¬ μ λ΅μ΄ κ°λ₯ν ν νλ ₯μ μ΄κ³ ν¨μ¨μ μΈμ§ νμΈνμμμ€. experimental_useSyncExternalStoreλ κ·Έ λͺ©νλ₯Ό λ¬μ±νλ λ° ν΅μ¬μ μΈ λꡬμ
λλ€.
μ£Όμ μμ :
- ꡬλ
λ‘μ§ λ¨μν: μλ
useEffectꡬλ λ° μ 리λ₯Ό μΆμνν©λλ€. - μ±λ₯ ν₯μ: Reactμ λ΄λΆ μ΅μ ν(μΌκ΄ μ²λ¦¬ λ° μ€λλ λ°μ΄ν° μ½κΈ° λ°©μ§)μ μ΄μ μ λ립λλ€.
- μ λ’°μ± λ³΄μ₯: λ©λͺ¨λ¦¬ λμ λ° κ²½μ μνμ κ΄λ ¨λ λ²κ·Έλ₯Ό μ€μ λλ€.
- λμμ± μμ©: λμμ± Reactμ μννκ² μλνλ μ ν리μΌμ΄μ μ ꡬμΆν©λλ€.
- SSR μ§μ: μλ² λ λλ§ μ ν리μΌμ΄μ μ μ νν μ΄κΈ° μνλ₯Ό μ 곡ν©λλ€.
- κΈλ‘λ² μ€λΉμ±: λ€μν λ€νΈμν¬ μ‘°κ±΄κ³Ό μ§μμ κ±Έμ³ μ¬μ©μ κ²½νμ ν₯μμν΅λλ€.
μ€νμ μ΄μ§λ§, μ΄ ν μ React μν κ΄λ¦¬μ λ―Έλλ₯Ό μΏλ³Ό μ μλ κ°λ ₯ν κΈ°νλ₯Ό μ 곡ν©λλ€. μμ μ μΈ λ¦΄λ¦¬μ€λ₯Ό κΈ°λνλ©° λ€μ κΈλ‘λ² νλ‘μ νΈμ μ μ€νκ² ν΅ν©ν΄ 보μμμ€!