- ItemMasterDataManagement 컴포넌트 구조화 (tabs, dialogs, components 분리) - HierarchyTab 타입 에러 수정 (BOMItem section_id, updated_at 추가) - API 클라이언트 구현 (item-master.ts, 13개 엔드포인트) - ItemMasterContext 구현 (상태 관리 및 데이터 흐름) - 백엔드 요구사항 문서 작성 (CORS 설정, API 스펙 등) - SSR 호환성 수정 (navigator API typeof window 체크) - 미사용 변수 ESLint 에러 해결 - Context 리팩토링 (AuthContext, RootProvider 추가) - API 유틸리티 추가 (error-handler, logger, transformers) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
93 lines
3.0 KiB
Markdown
93 lines
3.0 KiB
Markdown
# SSR Hydration 에러 해결 작업 기록
|
|
|
|
## 문제 상황
|
|
|
|
### 1차 에러: useData is not defined
|
|
- **위치**: ItemMasterDataManagement.tsx:389
|
|
- **원인**: 리팩토링 후 `useData()` → `useItemMaster()` 변경 누락
|
|
- **해결**: 함수 호출 변경
|
|
|
|
### 2차 에러: Hydration Mismatch
|
|
```
|
|
Hydration failed because the server rendered HTML didn't match the client
|
|
```
|
|
- **원인**: Context 파일에서 localStorage를 useState 초기화 시점에 접근
|
|
- **영향**: 서버는 초기값 렌더링, 클라이언트는 localStorage 데이터 렌더링 → HTML 불일치
|
|
|
|
## 근본 원인 분석
|
|
|
|
### ❌ 문제가 되는 패턴 (React SPA)
|
|
```typescript
|
|
const [data, setData] = useState(() => {
|
|
if (typeof window === 'undefined') return initialData;
|
|
const saved = localStorage.getItem('key');
|
|
return saved ? JSON.parse(saved) : initialData;
|
|
});
|
|
```
|
|
|
|
**문제점**:
|
|
- 서버: `typeof window === 'undefined'` → initialData 반환
|
|
- 클라이언트: localStorage 값 반환
|
|
- 결과: 서버/클라이언트 HTML 불일치 → Hydration 에러
|
|
|
|
### ✅ SSR-Safe 패턴 (Next.js)
|
|
```typescript
|
|
const [data, setData] = useState(initialData);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
const saved = localStorage.getItem('key');
|
|
if (saved) setData(JSON.parse(saved));
|
|
} catch (error) {
|
|
console.error('Failed to load data:', error);
|
|
localStorage.removeItem('key');
|
|
}
|
|
}, []);
|
|
```
|
|
|
|
**장점**:
|
|
- 서버/클라이언트 모두 동일한 초기값으로 렌더링
|
|
- useEffect는 클라이언트에서만 실행
|
|
- Hydration 후 localStorage 데이터로 업데이트
|
|
- 에러 처리로 손상된 데이터 복구
|
|
|
|
## 수정 내역
|
|
|
|
### AuthContext.tsx
|
|
- 2개 state: users, currentUser
|
|
- localStorage 로드를 단일 useEffect로 통합
|
|
- 에러 처리 추가
|
|
|
|
### ItemMasterContext.tsx
|
|
- 13개 state 전체 SSR-safe 패턴 적용
|
|
- 통합 useEffect로 모든 localStorage 로드 처리
|
|
- 버전 관리 유지:
|
|
- specificationMasters: v1.0
|
|
- materialItemNames: v1.1
|
|
- 포괄적 에러 처리 및 손상 데이터 정리
|
|
|
|
## 예상 부작용 및 완화
|
|
|
|
### Flash of Initial Content (FOIC)
|
|
- **현상**: 초기값 표시 → localStorage 데이터로 전환
|
|
- **영향**: 매우 짧은 시간 (보통 눈에 띄지 않음)
|
|
- **완화**: 필요시 loading state 추가 가능
|
|
|
|
### localStorage 데이터 손상
|
|
- **대응**: try-catch로 감싸고 손상 시 localStorage 클리어
|
|
- **결과**: 기본값으로 재시작하여 앱 정상 동작 유지
|
|
|
|
## 테스트 결과
|
|
- ✅ Hydration 에러 해결
|
|
- ✅ localStorage 정상 로드
|
|
- ✅ 서버/클라이언트 렌더링 일치
|
|
- ✅ 에러 없이 페이지 로드
|
|
|
|
## 향후 고려사항
|
|
- 나머지 8개 Context (Facilities, Accounting, HR, etc.)는 실제 사용 시 동일 패턴 적용 필요
|
|
- 복잡한 초기 데이터가 있는 경우 서버에서 데이터 pre-fetch 고려
|
|
- Critical한 초기 데이터는 서버 컴포넌트에서 직접 전달하는 방식 검토 가능
|
|
|
|
## 참고 문서
|
|
- Next.js SSR/Hydration: https://nextjs.org/docs/messages/react-hydration-error
|
|
- React useEffect: https://react.dev/reference/react/useEffect |