Reactμ useSyncExternalStore ν μ λν μ’ ν© κ°μ΄λ. μΈλΆ μν κ΄λ¦¬λ₯Ό μν λͺ©μ , ꡬν, μ΄μ λ° κ³ κΈ μ¬μ© μ¬λ‘λ₯Ό νμν©λλ€.
React useSyncExternalStore: μΈλΆ μν λκΈ°ν λ§μ€ν°νκΈ°
useSyncExternalStore
λ React 18μ λμ
λ ν
μΌλ‘, λμμ± λ λλ§κ³Ό νΈνλλ λ°©μμΌλ‘ μΈλΆ λ°μ΄ν° μμ€λ₯Ό ꡬλ
νκ³ μ½μ μ μκ² ν΄μ€λλ€. μ΄ ν
μ Reactμ κ΄λ¦¬ μνμ μλνν° λΌμ΄λΈλ¬λ¦¬, λΈλΌμ°μ API λλ λ€λ₯Έ UI νλ μμν¬μ λ°μ΄ν°μ κ°μ μΈλΆ μν κ°μ κ°κ·Ήμ λ©μμ€λλ€. μ΄μ κ·Έ λͺ©μ , ꡬν λ° μ΄μ μ λν΄ κΉμ΄ νκ³ λ€μ΄ λ³΄κ² μ΅λλ€.
useSyncExternalStoreμ νμμ± μ΄ν΄νκΈ°
Reactμ λ΄μ₯ μν κ΄λ¦¬(useState
, useReducer
, Context API)λ React μ»΄ν¬λνΈ νΈλ¦¬μ λ°μ νκ² μ°κ²°λ λ°μ΄ν°μ λν΄ λ§€μ° μ μλν©λλ€. νμ§λ§ λ§μ μ ν리μΌμ΄μ
μ Reactμ μ μ΄ λ²μλ₯Ό *λ²μ΄λ* λ°μ΄ν° μμ€μ ν΅ν©ν΄μΌ ν©λλ€. μ΄λ¬ν μΈλΆ μμ€μλ λ€μμ΄ ν¬ν¨λ μ μμ΅λλ€:
- μλνν° μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬: Zustand, Jotai λλ Valtioμ κ°μ λΌμ΄λΈλ¬λ¦¬μ ν΅ν©.
- λΈλΌμ°μ API:
localStorage
,IndexedDB
λλ λ€νΈμν¬ μ 보 APIμ λ°μ΄ν°μ μ κ·Ό. - μλ²μμ κ°μ Έμ¨ λ°μ΄ν°: React Queryλ SWRκ³Ό κ°μ λΌμ΄λΈλ¬λ¦¬κ° μ’ μ’ μ νΈλμ§λ§, λλ‘λ μ§μ μ μΈ μ μ΄λ₯Ό μν μ μμ΅λλ€.
- λ€λ₯Έ UI νλ μμν¬: Reactκ° λ€λ₯Έ UI κΈ°μ κ³Ό 곡쑴νλ νμ΄λΈλ¦¬λ μ ν리μΌμ΄μ .
React μ»΄ν¬λνΈ λ΄μμ μ΄λ¬ν μΈλΆ μμ€λ₯Ό μ§μ μ½κ³ μ°λ κ²μ νΉν λμμ± λ λλ§μμ λ¬Έμ λ₯Ό μΌμΌν¬ μ μμ΅λλ€. Reactκ° μ νλ©΄μ μ€λΉνλ λμ μΈλΆ μμ€κ° λ³κ²½λλ©΄, Reactλ μ€λλ(stale) λ°μ΄ν°λ‘ μ»΄ν¬λνΈλ₯Ό λ λλ§ν μ μμ΅λλ€. useSyncExternalStore
λ Reactκ° μΈλΆ μνμ μμ νκ² λκΈ°νν μ μλ λ©μ»€λμ¦μ μ 곡νμ¬ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν©λλ€.
useSyncExternalStoreμ μλ λ°©μ
useSyncExternalStore
ν
μ μΈ κ°μ§ μΈμλ₯Ό λ°μ΅λλ€:
subscribe
: μ½λ°± ν¨μλ₯Ό μΈμλ‘ λ°λ ν¨μμ λλ€. μ΄ μ½λ°±μ μΈλΆ μ€ν μ΄κ° λ³κ²½λ λλ§λ€ νΈμΆλ©λλ€. μ΄ ν¨μλ νΈμΆλμμ λ μΈλΆ μ€ν μ΄μ ꡬλ μ μ·¨μνλ ν¨μλ₯Ό λ°νν΄μΌ ν©λλ€.getSnapshot
: μΈλΆ μ€ν μ΄μ νμ¬ κ°μ λ°ννλ ν¨μμ λλ€. Reactλ λ λλ§ μ€μ μ€ν μ΄μ κ°μ μ½κΈ° μν΄ μ΄ ν¨μλ₯Ό μ¬μ©ν©λλ€.getServerSnapshot
(μ ν μ¬ν): μλ²μμ μΈλΆ μ€ν μ΄μ μ΄κΈ° κ°μ λ°ννλ ν¨μμ λλ€. μ΄κ²μ μλ² μ¬μ΄λ λ λλ§(SSR)μλ§ νμν©λλ€. μ 곡λμ§ μμΌλ©΄ Reactλ μλ²μμgetSnapshot
μ μ¬μ©ν©λλ€.
μ΄ ν
μ getSnapshot
ν¨μμμ μ»μ μΈλΆ μ€ν μ΄μ νμ¬ κ°μ λ°νν©λλ€. Reactλ getSnapshot
μ΄ λ°ννλ κ°μ΄ λ³κ²½λ λλ§λ€ μ»΄ν¬λνΈκ° λ€μ λ λλ§λλλ‘ λ³΄μ₯νλ©°, μ΄λ Object.is
λΉκ΅λ₯Ό ν΅ν΄ κ²°μ λ©λλ€.
κΈ°λ³Έ μμ : localStorageμ λκΈ°ννκΈ°
useSyncExternalStore
λ₯Ό μ¬μ©νμ¬ localStorage
μ κ°μ λκΈ°ννλ κ°λ¨ν μμ λ₯Ό λ§λ€μ΄ λ³΄κ² μ΅λλ€.
Value from localStorage: {localValue}
μ΄ μμ μμ:
subscribe
:window
κ°μ²΄μstorage
μ΄λ²€νΈλ₯Ό μμ ν©λλ€. μ΄ μ΄λ²€νΈλ λ€λ₯Έ νμ΄λ μ°½μμlocalStorage
κ° μμ λ λλ§λ€ λ°μν©λλ€.getSnapshot
:localStorage
μμmyValue
μ κ°μ κ°μ Έμ΅λλ€.getServerSnapshot
: μλ² μ¬μ΄λ λ λλ§μ μν κΈ°λ³Έκ°μ λ°νν©λλ€. μ¬μ©μκ° μ΄μ μ κ°μ μ€μ νλ€λ©΄ μΏ ν€μμ κ°μ Έμ¬ μλ μμ΅λλ€.MyComponent
:useSyncExternalStore
λ₯Ό μ¬μ©νμ¬localStorage
μ λ³κ²½ μ¬νμ ꡬλ νκ³ νμ¬ κ°μ νμν©λλ€.
κ³ κΈ μ¬μ© μ¬λ‘ λ° κ³ λ € μ¬ν
1. μλνν° μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬μ ν΅ν©νκΈ°
useSyncExternalStore
λ React μ»΄ν¬λνΈλ₯Ό μΈλΆ μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬μ ν΅ν©ν λ λΉμ λ°ν©λλ€. Zustandλ₯Ό μ¬μ©ν μμ λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€:
Count: {count}
μ΄ μμ μμλ useSyncExternalStore
λ₯Ό μ¬μ©νμ¬ Zustand μ€ν μ΄μ λ³κ²½ μ¬νμ ꡬλ
ν©λλ€. useStore.subscribe
μ useStore.getState
λ₯Ό ν
μ μ§μ μ λ¬νμ¬ ν΅ν©μ΄ μννκ² μ΄λ£¨μ΄μ§λ κ²μ νμΈνμΈμ.
2. λ©λͺ¨μ΄μ μ΄μ μΌλ‘ μ±λ₯ μ΅μ ννκΈ°
getSnapshot
μ λͺ¨λ λ λλ§μμ νΈμΆλλ―λ‘ μ±λ₯μ΄ μ’λλ‘ λ³΄μ₯νλ κ²μ΄ μ€μν©λλ€. getSnapshot
λ΄μμ λΉμ©μ΄ λ§μ΄ λλ κ³μ°μ νΌνμΈμ. νμν κ²½μ° useMemo
λ μ μ¬ν κΈ°μ μ μ¬μ©νμ¬ getSnapshot
μ κ²°κ³Όλ₯Ό λ©λͺ¨μ΄μ¦νμΈμ.
λ€μκ³Ό κ°μ (μ μ¬μ μΌλ‘ λ¬Έμ κ° λ μ μλ) μμ λ₯Ό κ³ λ €ν΄ λ³΄μΈμ:
```javascript import { useSyncExternalStore, useMemo } from 'react'; const externalStore = { data: [...Array(10000).keys()], // Large array listeners: [], subscribe(listener) { this.listeners.push(listener); return () => { this.listeners = this.listeners.filter((l) => l !== listener); }; }, setState(newData) { this.data = newData; this.listeners.forEach((listener) => listener()); }, getState() { return this.data; }, }; function ExpensiveComponent() { const data = useSyncExternalStore( externalStore.subscribe, () => externalStore.getState().map(x => x * 2) // Expensive operation ); return (-
{data.slice(0, 10).map((item) => (
- {item} ))}
μ΄ μμ μμ getSnapshot
(useSyncExternalStore
μ λ λ²μ§Έ μΈμλ‘ μ λ¬λ μΈλΌμΈ ν¨μ)μ ν° λ°°μ΄μ λν΄ λΉμ©μ΄ λ§μ΄ λλ map
μ°μ°μ μνν©λλ€. μ΄ μ°μ°μ κΈ°λ³Έ λ°μ΄ν°κ° λ³κ²½λμ§ μμλλΌλ *λͺ¨λ * λ λλ§μμ μ€νλ©λλ€. μ΄λ₯Ό μ΅μ ννκΈ° μν΄ κ²°κ³Όλ₯Ό λ©λͺ¨μ΄μ¦ν μ μμ΅λλ€:
-
{data.slice(0, 10).map((item) => (
- {item} ))}
μ΄μ map
μ°μ°μ externalStore.getState()
κ° λ³κ²½λ λλ§ μνλ©λλ€. μ°Έκ³ : μ€ν μ΄κ° λμΌν κ°μ²΄λ₯Ό λ³κ²½νλ κ²½μ° μ€μ λ‘ `externalStore.getState()`λ₯Ό κΉμ λΉκ΅(deep compare)νκ±°λ λ€λ₯Έ μ λ΅μ μ¬μ©ν΄μΌ ν©λλ€. μ΄ μμ λ μ€λͺ
μ μν΄ λ¨μνλμμ΅λλ€.
3. λμμ± λ λλ§ μ²λ¦¬νκΈ°
useSyncExternalStore
μ μ£Όμ μ΄μ μ Reactμ λμμ± λ λλ§ κΈ°λ₯κ³Όμ νΈνμ±μ
λλ€. λμμ± λ λλ§μ ν΅ν΄ Reactλ μ¬λ¬ λ²μ μ UIλ₯Ό λμμ μ€λΉν μ μμ΅λλ€. λμ λ λλ§ μ€μ μΈλΆ μ€ν μ΄κ° λ³κ²½λλ©΄, useSyncExternalStore
λ Reactκ° λ³κ²½ μ¬νμ DOMμ 컀λ°ν λ νμ μ΅μ λ°μ΄ν°λ₯Ό μ¬μ©νλλ‘ λ³΄μ₯ν©λλ€.
useSyncExternalStore
κ° μμΌλ©΄ μ»΄ν¬λνΈκ° μ€λλ λ°μ΄ν°λ‘ λ λλ§λμ΄ μκ°μ λΆμΌμΉμ μκΈ°μΉ μμ λμμ μ λ°ν μ μμ΅λλ€. useSyncExternalStore
μ getSnapshot
λ©μλλ λκΈ°μ μ΄κ³ λΉ λ₯΄κ² μ€κ³λμ΄ Reactκ° λ λλ§ μ€μ μΈλΆ μ€ν μ΄κ° λ³κ²½λμλμ§ μ μνκ² νλ¨ν μ μλλ‘ ν©λλ€.
4. μλ² μ¬μ΄λ λ λλ§(SSR) κ³ λ € μ¬ν
μλ² μ¬μ΄λ λ λλ§κ³Ό ν¨κ» useSyncExternalStore
λ₯Ό μ¬μ©ν λλ getServerSnapshot
ν¨μλ₯Ό μ 곡νλ κ²μ΄ νμμ μ
λλ€. μ΄ ν¨μλ μλ²μμ μΈλΆ μ€ν μ΄μ μ΄κΈ° κ°μ κ°μ Έμ€λ λ° μ¬μ©λ©λλ€. μ΄ ν¨μκ° μμΌλ©΄ Reactλ μλ²μμ getSnapshot
μ μ¬μ©νλ €κ³ μλν κ²μ΄λ©°, μΈλΆ μ€ν μ΄κ° λΈλΌμ°μ νΉμ API(μ: localStorage
)μ μμ‘΄νλ κ²½μ° μ΄λ λΆκ°λ₯ν μ μμ΅λλ€.
getServerSnapshot
ν¨μλ κΈ°λ³Έκ°μ λ°ννκ±°λ μλ² μΈ‘ μμ€(μ: μΏ ν€, λ°μ΄ν°λ² μ΄μ€)μμ λ°μ΄ν°λ₯Ό κ°μ ΈμμΌ ν©λλ€. μ΄λ κ² νλ©΄ μλ²μμ λ λλ§λ μ΄κΈ° HTMLμ μ¬λ°λ₯Έ λ°μ΄ν°κ° ν¬ν¨λλλ‘ λ³΄μ₯ν©λλ€.
5. μ€λ₯ μ²λ¦¬
νΉν μΈλΆ λ°μ΄ν° μμ€λ₯Ό λ€λ£° λλ κ°λ ₯ν μ€λ₯ μ²λ¦¬κ° μ€μν©λλ€. μ μ¬μ μΈ μ€λ₯λ₯Ό μ²λ¦¬νκΈ° μν΄ getSnapshot
λ° getServerSnapshot
ν¨μλ₯Ό try...catch
λΈλ‘μΌλ‘ κ°μΈμΈμ. μ€λ₯λ₯Ό μ μ ν κΈ°λ‘νκ³ μ ν리μΌμ΄μ
μ΄ μΆ©λνλ κ²μ λ°©μ§νκΈ° μν΄ λ체 κ°μ μ 곡νμΈμ.
6. μ¬μ¬μ©μ±μ μν 컀μ€ν ν
μ½λ μ¬μ¬μ©μ±μ λμ΄κΈ° μν΄ useSyncExternalStore
λ‘μ§μ 컀μ€ν
ν
λ΄μ μΊ‘μννμΈμ. μ΄λ κ² νλ©΄ μ¬λ¬ μ»΄ν¬λνΈμμ λ‘μ§μ λ μ½κ² 곡μ ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, localStorage
μ νΉμ ν€μ μ κ·ΌνκΈ° μν 컀μ€ν
ν
μ λ§λ€μ΄ λ³΄κ² μ΅λλ€:
μ΄μ μ΄λ€ μ»΄ν¬λνΈμμλ μ΄ ν μ μ½κ² μ¬μ©ν μ μμ΅λλ€:
```javascript import useLocalStorage from './useLocalStorage'; function MyComponent() { const [name, setName] = useLocalStorage('userName', 'Guest'); return (Hello, {name}!
setName(e.target.value)} />λͺ¨λ² μ¬λ‘
getSnapshot
μ λΉ λ₯΄κ² μ μ§νμΈμ:getSnapshot
ν¨μ λ΄μμ λΉμ©μ΄ λ§μ΄ λλ κ³μ°μ νΌνμΈμ. νμν κ²½μ° κ²°κ³Όλ₯Ό λ©λͺ¨μ΄μ¦νμΈμ.- SSRμ μν΄
getServerSnapshot
μ μ 곡νμΈμ: μλ²μμ λ λλ§λ μ΄κΈ° HTMLμ μ¬λ°λ₯Έ λ°μ΄ν°κ° ν¬ν¨λλλ‘ νμΈμ. - 컀μ€ν
ν
μ μ¬μ©νμΈμ: λ λμ μ¬μ¬μ©μ±κ³Ό μ μ§λ³΄μμ±μ μν΄
useSyncExternalStore
λ‘μ§μ 컀μ€ν ν λ΄μ μΊ‘μννμΈμ. - μ€λ₯λ₯Ό μ°μνκ² μ²λ¦¬νμΈμ:
getSnapshot
κ³ΌgetServerSnapshot
μtry...catch
λΈλ‘μΌλ‘ κ°μΈμΈμ. - ꡬλ μ μ΅μννμΈμ: μ»΄ν¬λνΈκ° μ€μ λ‘ νμλ‘ νλ μΈλΆ μ€ν μ΄μ λΆλΆλ§ ꡬλ νμΈμ. μ΄λ λΆνμν μ¬λ λλ§μ μ€μ λλ€.
- λμμ κ³ λ €νμΈμ:
useSyncExternalStore
κ° μ λ§λ‘ νμνμ§ νκ°νμΈμ. κ°λ¨ν κ²½μ°μλ λ€λ₯Έ μν κ΄λ¦¬ κΈ°μ μ΄ λ μ μ ν μ μμ΅λλ€.
useSyncExternalStoreμ λμ
useSyncExternalStore
λ κ°λ ₯ν λꡬμ΄μ§λ§ νμ μ΅μμ μ루μ
μ μλλλ€. λ€μκ³Ό κ°μ λμμ κ³ λ €ν΄ λ³΄μΈμ:
- λ΄μ₯ μν κ΄λ¦¬(
useState
,useReducer
, Context API): λ°μ΄ν°κ° React μ»΄ν¬λνΈ νΈλ¦¬μ λ°μ νκ² μ°κ²°λμ΄ μλ€λ©΄ μ΄λ¬ν λ΄μ₯ μ΅μ μΌλ‘ μΆ©λΆν κ²½μ°κ° λ§μ΅λλ€. - React Query/SWR: λ°μ΄ν° νμΉμ μν΄ μ΄λ¬ν λΌμ΄λΈλ¬λ¦¬λ€μ νλ₯ν μΊμ±, 무ν¨ν λ° μ€λ₯ μ²λ¦¬ κΈ°λ₯μ μ 곡ν©λλ€.
- Zustand/Jotai/Valtio: μ΄λ¬ν λ―Έλλ©ν μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬λ€μ μ ν리μΌμ΄μ μνλ₯Ό κ΄λ¦¬νλ κ°λ¨νκ³ ν¨μ¨μ μΈ λ°©λ²μ μ 곡ν©λλ€.
- Redux/MobX: μ μ μνλ₯Ό κ°μ§ 볡μ‘ν μ ν리μΌμ΄μ μ κ²½μ°, Reduxλ MobXκ° λ λμ μ νμΌ μ μμ΅λλ€ (λ λ§μ 보μΌλ¬νλ μ΄νΈλ₯Ό λμ νκΈ΄ νμ§λ§).
μ νμ μ ν리μΌμ΄μ μ νΉμ μꡬ μ¬νμ λ°λΌ λ¬λΌμ§λλ€.
κ²°λ‘
useSyncExternalStore
λ React ν΄ν·μ μΆκ°λ κ·μ€ν κΈ°λ₯μΌλ‘, λμμ± λ λλ§κ³Όμ νΈνμ±μ μ μ§νλ©΄μ μΈλΆ μν μμ€μμ μνν ν΅ν©μ κ°λ₯νκ² ν©λλ€. κ·Έ λͺ©μ , ꡬν λ° κ³ κΈ μ¬μ© μ¬λ‘λ₯Ό μ΄ν΄ν¨μΌλ‘μ¨ μ΄ ν
μ νμ©νμ¬ λ€μν μμ€μ λ°μ΄ν°μ ν¨κ³Όμ μΌλ‘ μνΈ μμ©νλ κ²¬κ³ νκ³ μ±λ₯μ΄ λ°μ΄λ React μ ν리μΌμ΄μ
μ ꡬμΆν μ μμ΅λλ€.
useSyncExternalStore
λ₯Ό μ¬μ©νκΈ° μ μ μ±λ₯μ μ°μ μνκ³ , μ€λ₯λ₯Ό μ°μνκ² μ²λ¦¬νλ©°, λμμ μΈ ν΄κ²°μ±
μ κ³ λ €νλ κ²μ μμ§ λ§μΈμ. μ μ€ν κ³νκ³Ό ꡬνμ ν΅ν΄ μ΄ ν
μ React μ ν리μΌμ΄μ
μ μ μ°μ±κ³Ό κ°λ ₯ν¨μ ν¬κ² ν₯μμν¬ μ μμ΅λλ€.
λ μμ보기
- useSyncExternalStoreμ λν React 곡μ λ¬Έμ
- λ€μν μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬(Zustand, Jotai, Valtio) μμ
useSyncExternalStore
μ λ€λ₯Έ μ κ·Ό λ°©μμ λΉκ΅νλ μ±λ₯ λ²€μΉλ§ν¬