useSyncExternalStore
useSyncExternalStore
๋ ์ธ๋ถ store๋ฅผ ๊ตฌ๋
ํ ์ ์๋ React Hook์
๋๋ค.
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
๋ ํผ๋ฐ์ค
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useSyncExternalStore
๋ฅผ ํธ์ถํ์ฌ ์ธ๋ถ ๋ฐ์ดํฐ ์ ์ฅ์์์ ๊ฐ์ ์ฝ์ต๋๋ค.
import { useSyncExternalStore } from 'react';
import { todosStore } from './todoStore.js';
function TodosApp() {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
// ...
}
store์ ์๋ ๋ฐ์ดํฐ์ ์ค๋ ์ท์ ๋ฐํํฉ๋๋ค. ๋ ๊ฐ์ ํจ์๋ฅผ ์ธ์๋ก ์ ๋ฌํด์ผ ํฉ๋๋ค.
subscribe
ํจ์๋ store๋ฅผ ๊ตฌ๋ ํ๊ณ ๊ตฌ๋ ์ ์ทจ์ํ๋ ํจ์๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.getSnapshot
ํจ์๋ store์์ ๋ฐ์ดํฐ์ ์ค๋ ์ท์ ์ฝ์ด์ผ ํฉ๋๋ค.
ํ๋ผ๋ฏธํฐ
-
subscribe
: ํ๋์callback
์ธ์๋ฅผ ๋ฐ์ store์ ๊ตฌ๋ ํ๋ ํจ์์ ๋๋ค. ์คํ ์ด๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ ๊ณต๋callback
์ ํธ์ถํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ฉ๋๋ค. subscribe ํจ์๋ ๊ตฌ๋ ์ ์ ๋ฆฌํ๋ ํจ์๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. -
getSnapshot
: ์ปดํฌ๋ํธ์ ํ์ํ store ๋ฐ์ดํฐ์ ์ค๋ ์ท์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ์คํ ์ด๊ฐ ๋ณ๊ฒฝ๋์ง ์์ ์ํ์์getSnapshot
์ ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถํ๋ฉด ๋์ผํ ๊ฐ์ ๋ฐํํด์ผ ํฉ๋๋ค. ์ ์ฅ์๊ฐ ๋ณ๊ฒฝ๋์ด ๋ฐํ๋ ๊ฐ์ด ๋ค๋ฅด๋ฉด (Object.is
์ ๋น๊ตํ์ฌ) React๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋งํฉ๋๋ค. -
optional
getServerSnapshot
: store์ ์๋ ๋ฐ์ดํฐ์ ์ด๊ธฐ ์ค๋ ์ท์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ์๋ฒ ๋ ๋๋ง ๋์ค๊ณผ ํด๋ผ์ด์ธํธ์์ ์๋ฒ ๋ ๋๋ง ๋ ์ฝํ ์ธ ์ ํ์ด๋๋ ์ด์ ์ค์๋ง ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฒ ์ค๋ ์ท์ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ๋์ผํด์ผ ํ๋ฉฐ ์ผ๋ฐ์ ์ผ๋ก ์ง๋ ฌํ๋์ด ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ์ ๋ฌ๋ฉ๋๋ค. ์ด ํจ์๊ฐ ์ ๊ณต๋์ง ์์ผ๋ฉด ์๋ฒ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ฐํ ๊ฐ
๋ ๋๋ง ๋ก์ง์ ์ฌ์ฉํ ์ ์๋ store์ ํ์ฌ ์ค๋ ์ท์ ๋๋ค.
์ฃผ์ ์ฌํญ
-
getSnapshot
์ด ๋ฐํํ๋ store ์ค๋ ์ท์ ๋ถ๋ณ์ด์ด์ผ ํฉ๋๋ค. ๊ธฐ๋ณธ ์คํ ์ด์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ ์ค๋ ์ท์ ๋ฐํํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์บ์ ๋ ๋ง์ง๋ง ์ค๋ ์ท์ ๋ฐํํฉ๋๋ค. -
๋ฆฌ๋ ๋๋งํ๋ ๋์ ๋ค๋ฅธ
subscribe
ํจ์๊ฐ ์ ๋ฌ๋๋ฉด React๋ ์๋ก ์ ๋ฌ๋subscribe
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฅ์๋ฅผ ๋ค์ ๊ตฌ๋ ํฉ๋๋ค. ์ปดํฌ๋ํธ ์ธ๋ถ์์subscribe
๋ฅผ ์ ์ธํ๋ฉด ์ด๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค. -
If the store is mutated during a non-blocking transition update, React will fall back to performing that update as blocking. Specifically, React will call
getSnapshot
a second time just before applying changes to the DOM. If it returns a different value than when it was called originally, React will restart the transition update from scratch, this time applying it as a blocking update, to ensure that every component on screen is reflecting the same version of the store. -
Itโs not recommended to suspend a render based on a store value returned by
useSyncExternalStore
. The reason is that mutations to the external store cannot be marked as non-blocking transition updates, so they will trigger the nearestSuspense
fallback, replacing already-rendered content on screen with a loading spinner, which typically makes a poor UX.For example, the following are discouraged:
const LazyProductDetailPage = lazy(() => import('./ProductDetailPage.js'));function ShoppingApp() {const selectedProductId = useSyncExternalStore(...);// โ Calling `use` with a Promise dependent on `selectedProductId`const data = use(fetchItem(selectedProductId))// โ Conditionally rendering a lazy component based on `selectedProductId`return selectedProductId != null ? <LazyProductDetailPage /> : <FeaturedProducts />;}
์ฌ์ฉ๋ฒ
์ธ๋ถ store ๊ตฌ๋
๋๋ถ๋ถ์ React ์ปดํฌ๋ํธ๋ props, state, ๊ทธ๋ฆฌ๊ณ context์์๋ง ๋ฐ์ดํฐ๋ฅผ ์ฝ์ต๋๋ค. ํ์ง๋ง ๋๋ก๋ ์ปดํฌ๋ํธ๊ฐ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋๋ React ์ธ๋ถ์ ์ผ๋ถ ์ ์ฅ์์์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ๋ค์์ด ํฌํจ๋ฉ๋๋ค.
- React ์ธ๋ถ์ state๋ฅผ ๋ณด๊ดํ๋ ์๋ํํฐ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ.
- ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ๋ ธ์ถํ๋ ๋ธ๋ผ์ฐ์ API์ ๊ทธ ๋ณ๊ฒฝ ์ฌํญ์ ๊ตฌ๋ ํ๋ ์ด๋ฒคํธ.
์ธ๋ถ ๋ฐ์ดํฐ ์ ์ฅ์์์ ๊ฐ์ ์ฝ์ผ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useSyncExternalStore
๋ฅผ ํธ์ถํ์ธ์.
import { useSyncExternalStore } from 'react';
import { todosStore } from './todoStore.js';
function TodosApp() {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
// ...
}
store์ ์๋ ๋ฐ์ดํฐ์ snapshot์ ๋ฐํํฉ๋๋ค. ๋ ๊ฐ์ ํจ์๋ฅผ ์ธ์๋ก ์ ๋ฌํด์ผ ํฉ๋๋ค.
subscribe
ํจ์๋ store์ ๊ตฌ๋ ํ๊ณ ๊ตฌ๋ ์ ์ทจ์ํ๋ ํจ์๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.getSnapshot
ํจ์ ํจ์๋ store์์ ๋ฐ์ดํฐ์ ์ค๋ ์ท์ ์ฝ์ด์ผ ํฉ๋๋ค.
React๋ ์ด ํจ์๋ฅผ ์ฌ์ฉํด ์ปดํฌ๋ํธ๋ฅผ store์ ๊ตฌ๋ ํ ์ํ๋ก ์ ์งํ๊ณ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ ๋ ๋ฆฌ๋ ๋๋งํฉ๋๋ค.
์๋ฅผ ๋ค์ด ์๋ ์๋๋ฐ์ค์์ todosStore
๋ React ์ธ๋ถ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ธ๋ถ store๋ก ๊ตฌํ๋์ด ์์ต๋๋ค. TodosApp
์ปดํฌ๋ํธ๋ useSyncExternalStore
Hook์ผ๋ก ํด๋น ์ธ๋ถ store์ ์ฐ๊ฒฐํฉ๋๋ค.
import { useSyncExternalStore } from 'react'; import { todosStore } from './todoStore.js'; export default function TodosApp() { const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot); return ( <> <button onClick={() => todosStore.addTodo()}>Add todo</button> <hr /> <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </> ); }
๋ธ๋ผ์ฐ์ API ๊ตฌ๋
useSyncExternalStore
๋ฅผ ์ถ๊ฐํ๋ ๋ ๋ค๋ฅธ ์ด์ ๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋๋ ๋ธ๋ผ์ฐ์ ์ ๋
ธ์ถ๋๋ ์ผ๋ถ ๊ฐ์ ๊ตฌ๋
ํ๋ ค๋ ๊ฒฝ์ฐ์
๋๋ค. ์๋ฅผ ๋ค์ด ์ปดํฌ๋ํธ์ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ํ์ฑํ๋์ด ์๋์ง ์ฌ๋ถ๋ฅผ ํ์ํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ navigator.onLine
.์ด๋ผ๋ ์์ฑ์ ํตํด ์ด ์ ๋ณด๋ฅผ ๋
ธ์ถํฉ๋๋ค.
์ด ๊ฐ์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ React๊ฐ ์์ง ๋ชปํ๋ ์ฌ์ด์ ๋ณ๊ฒฝ๋ ์ ์์ผ๋ฏ๋ก useSyncExternalStore
๋ก ๊ฐ์ ์ฝ์ด์ผ ํฉ๋๋ค.
import { useSyncExternalStore } from 'react';
function ChatIndicator() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// ...
}
getSnapshot
ํจ์๋ฅผ ๊ตฌํํ๋ ค๋ฉด ๋ธ๋ผ์ฐ์ API์์ ํ์ฌ ๊ฐ์ ์ฝ์ต๋๋ค.
function getSnapshot() {
return navigator.onLine;
}
๋ค์์ผ๋ก subscribe
ํจ์๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด navigator.onLine
์ด ๋ณ๊ฒฝ๋๋ฉด ๋ธ๋ผ์ฐ์ ๋ window
๊ฐ์ฒด์์ online
๋ฐ offline
์ด๋ฒคํธ๋ฅผ ์คํํฉ๋๋ค. callback
์ธ์๋ฅผ ํด๋น ์ด๋ฒคํธ์ ๊ตฌ๋
ํ ๋ค์ ๊ตฌ๋
์ ์ ๋ฆฌํ๋ ํจ์๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.
function subscribe(callback) {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
}
์ด์ React๋ ์ธ๋ถ navigator.onLine
API์์ ๊ฐ์ ์ฝ๋ ๋ฐฉ๋ฒ๊ณผ ๊ทธ ๋ณ๊ฒฝ ์ฌํญ์ ๊ตฌ๋
ํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ์์ต๋๋ค. ๋คํธ์ํฌ์์ ๋๋ฐ์ด์ค์ ์ฐ๊ฒฐ์ ๋์ด๋ณด๋ฉด ์ปดํฌ๋ํธ๊ฐ ์๋ต์ผ๋ก ๋ฆฌ๋ ๋๋ง๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
import { useSyncExternalStore } from 'react'; export default function ChatIndicator() { const isOnline = useSyncExternalStore(subscribe, getSnapshot); return <h1>{isOnline ? 'โ Online' : 'โ Disconnected'}</h1>; } function getSnapshot() { return navigator.onLine; } function subscribe(callback) { window.addEventListener('online', callback); window.addEventListener('offline', callback); return () => { window.removeEventListener('online', callback); window.removeEventListener('offline', callback); }; }
custom Hook์ผ๋ก ๋ก์ง ์ถ์ถํ๊ธฐ
์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ์์ ์ง์ useSyncExternalStore
๋ฅผ ์์ฑํ์ง๋ ์์ต๋๋ค. ๋์ ์ผ๋ฐ์ ์ผ๋ก custom Hook์์ ํธ์ถํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์๋ก ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๋์ผํ ์ธ๋ถ ์ ์ฅ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์ด custom useOnlineStatus
Hook์ ๋คํธ์ํฌ๊ฐ ์จ๋ผ์ธ ์ํ์ธ์ง ์ฌ๋ถ๋ฅผ ์ถ์ ํฉ๋๋ค.
import { useSyncExternalStore } from 'react';
export function useOnlineStatus() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
return isOnline;
}
function getSnapshot() {
// ...
}
function subscribe(callback) {
// ...
}
์ด์ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๊ธฐ๋ณธ ๊ตฌํ์ ๋ฐ๋ณตํ์ง ์๊ณ ๋ useOnlineStatus
๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
import { useOnlineStatus } from './useOnlineStatus.js'; function StatusBar() { const isOnline = useOnlineStatus(); return <h1>{isOnline ? 'โ Online' : 'โ Disconnected'}</h1>; } function SaveButton() { const isOnline = useOnlineStatus(); function handleSaveClick() { console.log('โ Progress saved'); } return ( <button disabled={!isOnline} onClick={handleSaveClick}> {isOnline ? 'Save progress' : 'Reconnecting...'} </button> ); } export default function App() { return ( <> <SaveButton /> <StatusBar /> </> ); }
์๋ฒ ๋ ๋๋ง ์ง์ ์ถ๊ฐ
React ์ฑ์ด server rendering์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ React ์ปดํฌ๋ํธ๋ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ ์ธ๋ถ์์๋ ์คํ๋์ด ์ด๊ธฐ HTML์ ์์ฑํฉ๋๋ค. ์ด๋ก ์ธํด ์ธ๋ถ store์ ์ฐ๊ฒฐํ ๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ์ ์ฉ API์ ์ฐ๊ฒฐํ๋ ๊ฒฝ์ฐ ์๋ฒ์ ํด๋น API๊ฐ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ์๋ํ์ง ์์ต๋๋ค.
- third-party ๋ฐ์ดํฐ ์ ์ฅ์์ ์ฐ๊ฒฐํ๋ ๊ฒฝ์ฐ ์๋ฒ์ ํด๋ผ์ด์ธํธ ๊ฐ์ ์ผ์นํ๋ ๋ฐ์ดํฐ๊ฐ ํ์ํฉ๋๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด getServerSnapshot
ํจ์๋ฅผ useSyncExternalStore
์ ์ธ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌํ์ธ์.
import { useSyncExternalStore } from 'react';
export function useOnlineStatus() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
return isOnline;
}
function getSnapshot() {
return navigator.onLine;
}
function getServerSnapshot() {
return true; // ์๋ฒ์์ ์์ฑ๋ HTML์๋ ํญ์ "Online"์ ํ์ํฉ๋๋ค.
}
function subscribe(callback) {
// ...
}
getServerSnapshot
ํจ์๋ getSnapshot
๊ณผ ์ ์ฌํ์ง๋ง ๋ ๊ฐ์ง ์ํฉ์์๋ง ์คํ๋ฉ๋๋ค.
- HTML์ ์์ฑํ ๋ ์๋ฒ์์ ์คํ๋ฉ๋๋ค.
- hydration ์ค ์ฆ React๊ฐ ์๋ฒ HTML์ ๊ฐ์ ธ์์ ์ธํฐ๋ํฐ๋ธํ๊ฒ ๋ง๋ค ๋ ํด๋ผ์ด์ธํธ์์ ์คํ๋ฉ๋๋ค.
์ด๋ฅผ ํตํด ์ฑ์ด ์ํธ์์ฉํ๊ธฐ ์ ์ ์ฌ์ฉ๋ ์ด๊ธฐ ์ค๋ ์ท ๊ฐ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ์๋ฒ ๋ ๋๋ง์ ์๋ฏธ ์๋ ์ด๊ธฐ๊ฐ์ด ์๋ค๋ฉด ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ์์๋ง ๋ ๋๋ง๋๋๋ก ๊ฐ์ ์ค์ ํ ์ ์์ต๋๋ค.
ํธ๋ฌ๋ธ ์ํ
์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: โgetSnapshot
์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํด์ผ ํฉ๋๋ค.โ
์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด getSnapshot
ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋ค ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค๋ ์๋ฏธ์
๋๋ค.
function getSnapshot() {
// ๐ด getSnapshot์์ ํญ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฐํํ์ง ๋ง์ธ์.
return {
todos: myStore.todos
};
}
React๋ getSnapshot
๋ฐํ ๊ฐ์ด ์ง๋๋ฒ๊ณผ ๋ค๋ฅด๋ฉด ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋งํฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํญ์ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ๋ฉด ๋ฌดํ ๋ฃจํ์ ๋ค์ด๊ฐ์ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ค์ ๋ก ๋ณ๊ฒฝ๋ ์ฌํญ์ด ์๋ ๊ฒฝ์ฐ์๋ง getSnapshot
๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. store์ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ง์ ๋ฐํํ ์ ์์ต๋๋ค.
function getSnapshot() {
// โ
๋ถ๋ณ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
return myStore.todos;
}
store ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฒฝ์ฐ getSnapshot
ํจ์๋ ํด๋น ๋ฐ์ดํฐ์ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ค๋
์ท์ ๋ฐํํด์ผ ํฉ๋๋ค. ์ฆ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ผ ํ์ง๋ง ๋งค๋ฒ ํธ์ถํ ๋๋ง๋ค ์ด ์์
์ ์ํํด์๋ ์ ๋ฉ๋๋ค. ๋์ ๋ง์ง๋ง์ผ๋ก ๊ณ์ฐ๋ ์ค๋
์ท์ ์ ์ฅํ๊ณ ์ ์ฅ์์ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์์ ๊ฒฝ์ฐ ์ง๋๋ฒ๊ณผ ๋์ผํ ์ค๋
์ท์ ๋ฐํํด์ผ ํฉ๋๋ค. ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ ์ฅ์๊ฐ ๊ตฌํ๋ ๋ฐฉ์์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค.
๋ฆฌ๋ ๋๋งํ ๋๋ง๋ค subscribe
ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค.
subscribe ํจ์๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ ์๋๋ฏ๋ก ๋ฆฌ๋ ๋๋งํ ๋๋ง๋ค ๋ฌ๋ผ์ง๋๋ค.
function ChatIndicator() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// ๐ฉํญ์ ๋ค๋ฅธ ํจ์๋ฅผ ์ฌ์ฉํ๋ฏ๋ก React๋ ๋ ๋๋งํ ๋๋ง๋ค ๋ค์ ๊ตฌ๋
ํฉ๋๋ค.
function subscribe() {
// ...
}
// ...
}
๋ฆฌ๋ ๋๋ง ์ฌ์ด์ ๋ค๋ฅธ subscribe
ํจ์๋ฅผ ์ ๋ฌํ๋ฉด React๊ฐ store๋ฅผ ๋ค์ ๊ตฌ๋
ํฉ๋๋ค. ์ด๋ก ์ธํด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ณ store ์ฌ๊ตฌ๋
์ ํผํ๊ณ ์ถ๋ค๋ฉด subscribe
ํจ์๋ฅผ ์ธ๋ถ๋ก ์ด๋ํ์ธ์.
function ChatIndicator() {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// ...
}
// โ
ํญ์ ๋์ผํ ํจ์์ด๋ฏ๋ก React๋ ๋ค์ ๊ตฌ๋
ํ ํ์๊ฐ ์์ต๋๋ค.
function subscribe() {
// ...
}
๋๋ ์ผ๋ถ ์ธ์๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ค์ ๊ตฌ๋
ํ๋๋ก subscribe
์ useCallback
์ผ๋ก ๋ํํฉ๋๋ค.
function ChatIndicator({ userId }) {
const isOnline = useSyncExternalStore(subscribe, getSnapshot);
// โ
userId๊ฐ ๋ณ๊ฒฝ๋์ง ์๋ ํ ๋์ผํ ํจ์์
๋๋ค.
const subscribe = useCallback(() => {
// ...
}, [userId]);
// ...
}