User, WorkspaceList, Workspace, SelectedMom 등은 결국 서버 상태라서 react-query(1.28 MB) 사용해도 좋아보여요.
처음에 생각했던 Recoil / Jotai를 사용한다면 번들 사이즈도 작고(2.21 MB > 389 kB) 유지보수도 활발하게 이루어지고 있는 Jotai를 쓰는게 좋을 것 같아요.
<aside> ⛳ 멀리 떨어져있는 컴포넌트 간에 공유하는 상태를 보다 atomic하게 관리하고 memo 사용하지 않고도 불필요한 렌더링이 발생하지 않도록 하기 위함
</aside>
내부에 소켓 이벤트들이 있어서 그렇지 상태만 뽑아놓으니 생각보다 간단해요.
<**UserContext**.Provider value={{ user, setUser }}>
<Routes>
<Route path="/" element={<LoginPage />} />
<Route path="/oauth" element={<OAuthPage />} />
<Route path="/workspace/*" element={<WorkspacePage />} />
<Route path="/404" element={<NotFoundPage />} />
</Routes>
</UserContext.Provider>
<Suspense fallback={<WorkspaceSkeleton />}>
<**WorkspacesContext**.Provider value={{ workspaces, setWorkspaces }}>
{isLoaded ? (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<DefaultWorkspace />} />
<Route path="/:id/*" element={<Workspace />} />
</Route>
</Routes>
) : (
<WorkspaceSkeleton />
)}
</WorkspacesContext.Provider>
</Suspense>
<**SocketContext**.Provider value={memoizedSocketValue}>
<**MeetingContext**.Provider value={memoizedOnGoingValue}>
{**workspace** && ( // 현재 Recoil atom, 기존 코드에서는 Context 사용
<**SelectedMomContext**.Provider value={{ selectedMom, setSelectedMom }}>
<Sidebar />
{workspace.moms.length ? <Mom /> : <DefaultMom />}
</SelectedMomContext.Provider>
)}
{isOnGoing && <MeetingMediaBar />}
</MeetingContext.Provider>
</SocketContext.Provider>
User
export type User = {
id: number;
name: string;
avatarUrl: string;
};
Workspaces
interface IWorkspceContext {
workspaces: Workspace[];
setWorkspaces: React.Dispatch<React.SetStateAction<Workspace[]>>;
}
export interface Workspace {
id: number;
name: string;
code: string;
}
Workspace
export type WorkspaceInfo = {
name: string;
members: User[];
moms: Mom[];
};
Socket
interface ISocketContext {
momSocket: Socket;
workspaceSocket: Socket;
}
Selected Mom
interface IMomContext {
selectedMom: TMom | null;
setSelectedMom: React.Dispatch<React.SetStateAction<TMom | null>>;
}
export type TMom = {
_id: string;
title: string;
createdAt: Date;
};
Meeting
interface IMeetingContext {
isOnGoing: boolean;
setIsOnGoing: Dispatch<SetStateAction<boolean>>;
}