CastCanvas Lab: React Flow와 Zustand를 이용한 무한 캔버스 연구 공간 구축
단순히 문서를 읽는 것을 넘어, 정보를 공간적으로 배치하고 연결할 수 있는 ‘무한 캔버스’ 기반의 연구 워크스페이스를 만들기 위한 첫 발을 뗐다. 초기 환경 설정부터 핵심 캔버스 엔진, 그리고 노드 정보 수정이 가능한 인스펙터 패널까지의 구현 과정을 정리한다.
목표
- 확장 가능한 캔버스 아키텍처: React Flow를 활용하여 무한 캔버스 환경 구축
- 중앙 집중식 상태 관리: Zustand를 통해 노드와 엣지의 상태를 선언적으로 관리
- 다양한 에셋 지원: PDF 문서, 이미지, 노트를 동일한 수준의 캔버스 자산으로 취급
- 디자인 시스템 구축: CSS 변수 기반의 테마(Light/Dark) 시스템 적용
핵심 구현 포인트
1) Zustand와 React Flow의 결합 (State Orchestration)
캔버스의 모든 상태(노드, 엣지, 선택된 요소 등)를 Zustand 스토어에서 관리함으로써, 복잡한 캔버스 로직을 UI 컴포넌트와 분리했다.
// src/features/canvas/stores/useCanvasStore.ts (개념적 구조)
export const useCanvasStore = create<CanvasState>((set, get) => ({
nodes: [],
edges: [],
onNodesChange: (changes) => {
set({ nodes: applyNodeChanges(changes, get().nodes) });
},
// 노드 추가 및 선택 상태 관리 로직...
}));
2) 커스텀 노드 시스템 (Specialized Node Types)
DocumentNode, ImageNode, NoteNode 등 다양한 데이터 타입을 처리하기 위해 React Flow의 nodeTypes를 확장했다. 각 노드는 고유한 렌더링 로직을 가지며, CSS 변수를 통해 일관된 스타일을 유지한다.
// src/features/canvas/nodeTypes.ts
export const nodeTypes = {
documentNode: DocumentNode,
imageNode: ImageNode,
noteNode: NoteNode,
};
트러블슈팅 / 고민 포인트
노드 선택 시 성능 및 UI 반응성
- 문제: 수많은 노드가 캔버스에 배치될 때, 특정 노드를 선택하거나 드래그할 때 전체 캔버스가 리렌더링되는 성능 이슈 우려.
- 해결: Zustand의 선택적 구독(Selector)을 활용하여 필요한 컴포넌트만 업데이트되도록 최적화하고,
Inspector패널 노출 여부를 전역 상태로 관리하여 레이아웃 시프트를 최소화함.
결과
- 기본 캔버스 엔진 완비: 노드 추가, 삭제, 드래그, 줌/팬 기능 정상 작동
- 3종의 핵심 노드 구현: 문서, 이미지, 텍스트 메모 배치 가능
- 인스펙터 패널 통합: 선택된 노드의 상세 정보를 확인하고 수정할 수 있는 사이드바 구현
- 다크 모드 지원: 디자인 토큰 시스템을 통해 시스템 설정에 따른 테마 전환 가능
다음 개선 아이디어
- 실시간 협업(Yjs): 여러 사용자가 동시에 캔버스에서 작업할 수 있는 환경 구축
- PDF 텍스트 추출: PDF 노드 내의 텍스트를 검색하거나 노트로 복사하는 기능
- 엣지 강화: 노드 간의 관계를 더 명확하게 시각화하고 설명할 수 있는 기능