# Migration Guide: Moving to Phase 4 Architecture
## 🎯 Overview
This guide helps you migrate existing components to the new hook-based, JSON-driven architecture.
## 🚦 Migration Strategy
### Three Paths
#### Path 1: Hook Extraction (Recommended First)
**Best for:** Existing components with complex logic
**Time:** 1-2 hours per component
**Risk:** Low (backward compatible)
#### Path 2: Component Split
**Best for:** Large components (>150 LOC)
**Time:** 2-4 hours per component
**Risk:** Medium (requires refactoring)
#### Path 3: JSON Conversion
**Best for:** Simple, static pages
**Time:** 1-2 hours per page
**Risk:** Low (optional, new pattern)
## 📝 Path 1: Hook Extraction
### Step 1: Identify Business Logic
**Before:**
```typescript
function UserManager() {
const [users, setUsers] = useKV('users', [])
const [searchQuery, setSearchQuery] = useState('')
const [selectedId, setSelectedId] = useState(null)
const addUser = (user) => {
setUsers((prev) => [...prev, user])
}
const deleteUser = (id) => {
setUsers((prev) => prev.filter(u => u.id !== id))
}
const filteredUsers = users.filter(u =>
u.name.toLowerCase().includes(searchQuery.toLowerCase())
)
return (
{/* 100+ lines of JSX */}
)
}
```
### Step 2: Extract to Custom Hook
**Create hook:**
```typescript
// src/hooks/features/use-user-manager.ts
import { useArray, useSearch, useCRUD } from '@/hooks/data'
export function useUserManager() {
const { items: users, add, remove, update } = useArray('users', [])
const { query, setQuery, results } = useSearch(users, ['name', 'email'])
const { selected, setSelectedId } = useCRUD(results, () => {})
return {
users: results,
addUser: add,
deleteUser: remove,
updateUser: update,
searchQuery: query,
setSearchQuery: setQuery,
selectedUser: selected,
setSelectedUser: setSelectedId,
}
}
```
**After:**
```typescript
import { useUserManager } from '@/hooks/features/use-user-manager'
function UserManager() {
const {
users,
addUser,
deleteUser,
searchQuery,
setSearchQuery,
selectedUser,
} = useUserManager()
return (
{/* Same JSX, now cleaner */}
)
}
```
### Benefits
✅ Logic is reusable
✅ Component is smaller
✅ Easy to test
✅ Better organization
## 📏 Path 2: Component Split
### Step 1: Identify Sub-Components
**Before (200 LOC):**
```typescript
function ProjectDashboard({ files, models, components }) {
return (
Files
{/* 30 lines */}
Models
{/* 30 lines */}
Components
{/* 30 lines */}
{/* More sections... */}
)
}
```
### Step 2: Extract Sub-Components
**Create small components:**
```typescript
// src/components/dashboard/StatsCard.tsx (< 50 LOC)
interface StatsCardProps {
title: string
count: number
icon: React.ReactNode
onClick?: () => void
}
export function StatsCard({ title, count, icon, onClick }: StatsCardProps) {
return (
{icon}
{title}
{count}
)
}
```
**After (< 80 LOC):**
```typescript
import { StatsCard } from './dashboard/StatsCard'
function ProjectDashboard({ files, models, components }) {
return (
}
onClick={() => navigate('/files')}
/>
}
onClick={() => navigate('/models')}
/>
}
onClick={() => navigate('/components')}
/>
)
}
```
### Benefits
✅ Each component < 150 LOC
✅ Reusable sub-components
✅ Easier to understand
✅ Simpler to test
## 📄 Path 3: JSON Conversion
### Step 1: Analyze Page Structure
**Before:**
```typescript
function SettingsPage() {
const [name, setName] = useKV('app-name', '')
const [theme, setTheme] = useKV('app-theme', 'light')
return (
Settings
setName(e.target.value)} />
)
}
```
### Step 2: Create JSON Schema
**Create schema:**
```json
{
"id": "settings",
"name": "Settings",
"description": "Application settings page",
"layout": {
"type": "single"
},
"dataSources": [
{
"id": "appName",
"type": "kv",
"key": "app-name",
"defaultValue": ""
},
{
"id": "appTheme",
"type": "kv",
"key": "app-theme",
"defaultValue": "light"
}
],
"components": [
{
"id": "root",
"type": "Card",
"children": [
{
"id": "header",
"type": "CardHeader",
"children": [
{
"id": "title",
"type": "CardTitle",
"props": {
"children": "Settings"
}
}
]
},
{
"id": "content",
"type": "CardContent",
"props": {
"className": "space-y-4"
},
"children": [
{
"id": "name-input",
"type": "Input",
"dataBinding": "appName",
"props": {
"placeholder": "App Name"
}
},
{
"id": "save-button",
"type": "Button",
"props": {
"children": "Save"
},
"eventHandlers": {
"onClick": "save-settings"
}
}
]
}
]
}
],
"actions": [
{
"id": "save-settings",
"type": "custom",
"handler": "handleSave"
}
]
}
```
### Step 3: Use PageRenderer
**After:**
```typescript
import { PageRenderer } from '@/config/orchestration'
import settingsSchema from '@/config/pages/settings.json'
import { toast } from 'sonner'
function SettingsPage() {
const customHandlers = {
handleSave: () => {
toast.success('Settings saved!')
}
}
return (
)
}
```
### Benefits
✅ No React code needed
✅ Easy to modify structure
✅ Testable schemas
✅ Rapid prototyping
## 🎯 Decision Matrix
### When to Use Hooks
| Scenario | Use Hooks? |
|----------|-----------|
| Complex business logic | ✅ Yes |
| Reusable functionality | ✅ Yes |
| API integration | ✅ Yes |
| Form validation | ✅ Yes |
| State management | ✅ Yes |
### When to Split Components
| Scenario | Split? |
|----------|--------|
| Component > 150 LOC | ✅ Yes |
| Repeated UI patterns | ✅ Yes |
| Testing complexity | ✅ Yes |
| Hard to understand | ✅ Yes |
### When to Use JSON
| Scenario | Use JSON? |
|----------|-----------|
| Simple CRUD page | ✅ Yes |
| Form-heavy page | ✅ Yes |
| Dashboard/stats | ✅ Yes |
| Static content | ✅ Yes |
| Complex interactions | ❌ No (use hooks) |
| Custom animations | ❌ No (use React) |
## 📋 Migration Checklist
### For Each Component
- [ ] Measure LOC (Lines of Code)
- [ ] If > 150 LOC, plan to split
- [ ] Identify business logic to extract
- [ ] Create custom hooks
- [ ] Update component to use hooks
- [ ] Test thoroughly
- [ ] Consider JSON if applicable
- [ ] Document changes
### Quality Gates
- [ ] All components < 150 LOC
- [ ] Business logic in hooks
- [ ] No duplicate code
- [ ] Full type safety
- [ ] Tests passing
- [ ] Documentation updated
## 🔧 Tools & Helpers
### LOC Counter
```bash
# Count lines in a component
wc -l src/components/MyComponent.tsx
# Find large components
find src/components -name "*.tsx" -exec wc -l {} \; | sort -rn | head -20
```
### Hook Template
```typescript
import { useKV } from '@github/spark/hooks'
import { useCallback } from 'react'
export function useMyFeature() {
const [data, setData] = useKV('my-feature-data', [])
const operation = useCallback(() => {
// Logic here
}, [])
return {
data,
operation,
}
}
```
### JSON Schema Template
```json
{
"id": "my-page",
"name": "My Page",
"layout": { "type": "single" },
"dataSources": [],
"components": [],
"actions": []
}
```
## 📚 Learning Resources
### Read First
1. [QUICK_REFERENCE.md](./QUICK_REFERENCE.md) - Fast overview
2. [COMPLETE_HOOK_LIBRARY.md](../api/COMPLETE_HOOK_LIBRARY.md) - Hook details
3. [JSON_ORCHESTRATION_COMPLETE.md](../architecture/JSON_ORCHESTRATION_COMPLETE.md) - JSON guide
### Examples
- `/src/hooks/data/` - Hook implementations
- `/src/config/pages/` - JSON page examples
- `/src/components/` - Component examples
## 🆘 Common Issues
### Issue: Hook Violation
**Error:** "Hooks can only be called inside function components"
**Solution:** Ensure hooks are called at the top level, not in loops/conditions
```typescript
// ❌ Wrong
function MyComponent() {
if (condition) {
const data = useKV('key', []) // Hook in condition!
}
}
// ✅ Correct
function MyComponent() {
const data = useKV('key', [])
if (condition) {
// Use data here
}
}
```
### Issue: Stale Closure
**Error:** State updates don't reflect current values
**Solution:** Use functional updates
```typescript
// ❌ Wrong
const add = () => {
setItems([...items, newItem]) // items is stale!
}
// ✅ Correct
const add = () => {
setItems((current) => [...current, newItem])
}
```
### Issue: JSON Not Rendering
**Error:** Component not found in registry
**Solution:** Register component in component-registry.ts
```typescript
import { MyComponent } from '@/components/MyComponent'
export const ComponentRegistry = {
// ... other components
MyComponent,
}
```
## 🎉 Success Stories
### Before
- 500 LOC component
- Mixed concerns
- Hard to test
- Duplicate logic
### After
- 3 hooks (< 100 LOC each)
- 5 components (< 50 LOC each)
- Or 1 JSON schema (< 100 lines)
- Fully tested
- Reusable everywhere
## 🚀 Next Steps
1. Pick one component to migrate
2. Follow Path 1 (Hook Extraction)
3. Measure success (LOC reduction, testability)
4. Share learnings with team
5. Repeat for other components
---
**Need Help?**
- Check [INDEX.md](./INDEX.md) for documentation
- Review example hooks in `/src/hooks/`
- Study JSON examples in `/src/config/pages/`
- Ask questions in team chat
**Good luck with your migration! 🚀**