useCallback
나 useMemo
로 감싸주어야 했습니다.useSyncExternalStore
훅을 추가했습니다.useSyncExternalStore
외부 스토어에 구독할 수 있게 해주는 React 훅
반환값 : 외부 스토어 데이터의 snapshot을 반환함
subscribe
매개변수 : 스토어를 구독하고 구독 취소 함수를 반환하는 함수
callback
인수을 받고 스토어에 callback
을 등록함callback
함수가 실행되고 컴포넌트가 리렌더링됨getSnapshot
매개변수 : 스토어 데이터의 snapshot을 읽는 함수
getServerSnapshot
매개변수 (선택적) : 스토어 데이터의 초기 snapshot을 반환하는 함수
import { useSyncExternalStore } from 'react';
import { todosStore } from './todoStore.js';
function TodoApp() {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getsnapshot)
}
getSnapshot
으로부터 반환된 스토어 snapshot은 불변성이어야 함subscribe
함수가 전달될 경우, React는 새로 전달된 subscribe
함수를 사용함subscribe
함수를 선언하여 이를 방지할 수 있음// todoStore.js
let nextId = 0;
let todos = [{ id: nextId++, text: 'Todo #1' }];
let listeners = [];
export const todosStore = {
addTodo() {
todos = [...todos, { id: nextId++, text: 'Todo #' + nextId }]
emitChange();
},
subscribe(listener) {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter(l => l !== listener);
};
},
getSnapshot() {
return todos;
}
};
function emitChange() {
for (let listener of listeners) {
listener();
}
}
// App.js
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>
</>
);
}
useSyncExternalStore
를 사용해야 함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);
};
}
React 앱에서 server rendering을 사용할 때, 초기 HTML을 생성하기 위해 React 컴포넌트를 브라우저 환경 바깥에서도 실행함
이러한 문제들을 해결하기 위해 getServerSnapshot
매개변수에 함수를 전달함
getServerSnapshot
함수는 아래 2 가지 경우에만 실행됨