| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- javascript
- 크롤링
- contextBridge
- 백엔드
- Vite
- 배포
- 메일자동화
- 프론트엔드
- electron
- 도메인설계
- playwright
- 마이그레이션
- REST API
- sqlite
- next.js
- 온디바이스AI
- 아키텍처
- typescript
- 소셜로그인
- 보안
- 인증
- JWT
- 상태관리
- github actions
- Kotlin
- python
- Android
- React
- FastAPI
- php
- Today
- Total
HM소프트
스텝 위저드 UX와 전역 상태 설계 — 이미지 텍스트 교체 도구 (2) 본문

React 스텝 위저드의 상태 분산 문제를 useReducer와 Context 전역 상태로 푼 설계를 다룬다. 이미지·영역·줄·단어 4단 계층을 액션으로 불변 갱신하고, 변경 안 함을 null로 표현하며, OCR 비동기 상태와 단계 이동 규칙까지 한 곳에 모아 단계를 오가도 편집 내용이 보존되게 한 이미지 텍스트 교체 도구 사례다.
2편: 위저드와 상태
1편에서 OCR + 오버레이 엔진을 다뤘다. 이번 편은 그 엔진을 감싸는 사용자 흐름(UX)과 상태 설계다. 입력이 여러 종류라, 한 화면에 다 욱여넣지 않고 단계로 나눴다.
왜 스텝 위저드인가
이 도구는 한 번에 여러 종류의 입력을 받는다. 표 데이터, 카드형 항목, 이미지 갤러리, 부가 텍스트 정보. 이걸 한 화면에 다 펼치면 사용자가 압도된다. 그래서 스텝 위저드로 나눠, 한 단계에 하나의 관심사만 보여주고 마지막에 결과를 만든다.
먼저 위저드 레이아웃 셸(단계 표시, 이전/다음, 진행 상태)을 잡고, 각 단계를 그 위에 얹었다.
단계마다 다른 입력 방식
각 단계가 다루는 데이터가 달라서 구현 포인트도 제각각이었다.
표 데이터 입력 — 엑셀 업로드
값을 일일이 타이핑하지 않게, 엑셀 파일을 올리면 표로 파싱해 테이블에서 편집하게 했다. 대량 데이터를 한 번에 가져오는 가장 빠른 길이다.
import * as XLSX from "xlsx";
function parseExcel(file: File): Promise<Row[]> {
return file.arrayBuffer().then((buf) => {
const wb = XLSX.read(buf);
const sheet = wb.Sheets[wb.SheetNames[0]];
return XLSX.utils.sheet_to_json<Row>(sheet);
});
}
카드형 항목 — 드래그앤드롭 정렬
항목들을 카드로 만들고, 순서를 드래그앤드롭으로 바꾸게 했다. 순서가 의미 있는 데이터라, 직관적으로 재배치할 수 있어야 했다.
이미지 갤러리 관리
대표 이미지와 갤러리 이미지를 따로 관리하는 단계. 이미지 추가·삭제·교체를 다룬다.
부가 정보 입력
위치·시간 등 텍스트 정보를 입력받는 단계.
핵심: 전역 상태를 한 곳에 — EditorContext
위저드의 가장 큰 함정은 상태가 단계별로 흩어지는 것이다. 각 단계가 자기 상태를 따로 들면, "지금까지 입력한 전체"를 알기 어렵고 단계 간 데이터 공유가 꼬인다.
그래서 모든 단계의 데이터를 EditorContext 하나에 모았다. 단계는 화면일 뿐이고, 데이터는 Context가 들고 있다.
interface EditorState {
table: Row[];
cards: Card[];
gallery: ImageItem[];
info: ExtraInfo;
overlayNodes: OverlayNode[]; // 1편의 엔진 데이터
}
const EditorContext = createContext<{
state: EditorState;
update: (patch: Partial<EditorState>) => void;
} | null>(null);
// 어느 단계에서든 동일한 데이터에 접근
function useEditor() {
const ctx = useContext(EditorContext);
if (!ctx) throw new Error("EditorProvider 안에서 써야 합니다");
return ctx;
}
각 단계는 useEditor()로 필요한 부분만 읽고 쓴다. 어느 단계에 있든 "전체 상태"가 한 곳에 있으니, 마지막 미리보기/내보내기 단계에서 모든 입력을 한 번에 조합할 수 있다.
이 구조의 이점
- 단계 추가가 쉽다: 새 단계는 위저드 셸에 화면 하나 더 얹고, Context에 필드 하나 추가하면 된다.
- 단계 간 일관성: 모든 데이터가 한 곳이라, 2단계에서 입력한 값을 5단계에서 그대로 참조.
- 테스트·디버깅: "지금 상태가 뭐냐"가 Context 하나만 보면 된다.
정리하며
- 스텝 위저드로 여러 종류의 입력을 한 단계 한 관심사로 나눴다.
- 단계별 입력 방식(엑셀 업로드, 드래그앤드롭, 갤러리)을 각각에 맞게 구현.
- 전역 상태를 EditorContext 한 곳에 모아, 흩어지기 쉬운 위저드 상태의 일관성을 지켰다.
다음 마지막 3편에서는 실시간 미리보기와 html2canvas 내보내기로 시리즈를 마친다.
'기술 개발일지' 카테고리의 다른 글
| AI 코딩 에이전트용 디자인 시스템 플러그인 개발기 (1) — 'AI 티 나는 디자인'을 강제로 깨뜨리기 (0) | 2026.06.15 |
|---|---|
| 실시간 미리보기 + html2canvas 이미지 내보내기 — 텍스트 교체 도구 (3) (0) | 2026.06.12 |
| OCR + 오버레이 렌더링 엔진 만들기 — 이미지 텍스트 교체 도구 (1) (0) | 2026.06.12 |
| Vite + React 빌드·배포 트러블슈팅 — 장부 관리 앱 (2) (0) | 2026.06.12 |
| 에디토리얼 스타일 UI와 브랜드 아이덴티티 설계 — 장부 관리 앱 (1) (0) | 2026.06.12 |