---
name: hooks-validator
description: Validates React code for Rules of Hooks violations. Catches issues like hooks called after conditional returns that cause production crashes (React error #310). Use when creating or modifying screens, components, or custom hooks.
---
# React Hooks Validator
This skill analyzes React code to detect Rules of Hooks violations that cause production crashes.
## Background
The Ishkul codebase experienced a production crash (React error #310) in LessonScreen where hooks were called after conditional returns. This skill prevents similar issues.
## Rules of Hooks
React hooks must:
1. **Always be called at the top level** - Never inside loops, conditions, or nested functions
2. **Always be called in the same order** - On every render
3. **Only be called from React functions** - Components or custom hooks
## Validation Checklist
When analyzing React code, check for these violations:
### Critical Violations (Will Crash)
1. **Hooks after conditional returns**
```typescript
// BAD - Hook called after conditional return
export const Component = () => {
if (loading) return ;
const [state, setState] = useState(null); // Will crash!
return ;
};
// GOOD - All hooks at top
export const Component = () => {
const [state, setState] = useState(null);
if (loading) return ;
return ;
};
```
2. **Hooks inside conditionals**
```typescript
// BAD
if (user) {
const [data, setData] = useState(null);
}
// GOOD
const [data, setData] = useState(user ? null : undefined);
```
3. **Hooks inside loops**
```typescript
// BAD
items.forEach(() => {
const [itemState] = useState({});
});
// GOOD - Single state for all items
const [itemStates, setItemStates] = useState({});
```
4. **Hooks inside callbacks**
```typescript
// BAD
const handleClick = () => {
const [state] = useState(null);
};
// GOOD - Hook outside callback
const [state, setState] = useState(null);
const handleClick = () => {
setState(newValue);
};
```
### Ishkul-Specific Patterns
From the codebase patterns, ensure:
1. **Zustand store hooks at top**
```typescript
export const Screen = () => {
// All Zustand hooks first
const { lesson, isLoading, error } = useLessonStore();
const { courses } = useCoursesStore();
// Then other hooks
const { colors } = useTheme();
const navigation = useNavigation();
// Extract state used in multiple render paths BEFORE conditionals
const completedBlocks = lesson?.completedBlocks ?? [];
// Callbacks with useCallback BEFORE conditionals
const handleSubmit = useCallback(() => {
// ...
}, [dependencies]);
// NOW safe to have conditional returns
if (isLoading) return ;
if (error) return ;
if (!lesson) return ;
return ;
};
```
2. **Custom hooks must follow same rules**
```typescript
// Custom hook in frontend/src/hooks/
export function useLesson(options: UseLessonOptions) {
// All hooks at top
const prevLessonIdRef = useRef(null);
const { currentLesson, fetchLesson } = useLessonStore();
const { getNextLesson } = useCoursesStore();
// Effects after hooks
useEffect(() => {
// ...
}, [deps]);
// Never return early before all hooks are called
return {
lesson: currentLesson,
// ...
};
}
```
## How to Analyze
When reviewing a file:
1. **List all hook calls** in order of appearance
2. **Check for early returns** that could cause hooks to be skipped
3. **Verify hooks are not inside**:
- if/else blocks
- for/while loops
- forEach/map callbacks
- Event handlers
- try/catch blocks (hooks should be outside)
4. **Check custom hooks** call other hooks at the top level
## Output Format
When violations are found, report:
```markdown
## Hooks Violations Found
### File: `path/to/file.tsx`
**Violation #1** (Critical)
- **Type**: Hook after conditional return
- **Line**: 45
- **Hook**: `useState`
- **Issue**: `useState` is called after `if (loading) return `
- **Fix**: Move `useState` before the conditional return
```typescript
// Current (line 42-48)
if (loading) return ;
const [data, setData] = useState(null);
// Fixed
const [data, setData] = useState(null);
if (loading) return ;
```
```
## Integration with Testing
After fixing hooks violations, ensure state transition tests exist:
```typescript
describe('State Transitions (Rules of Hooks)', () => {
it('should handle transition from loading to success', async () => {
const { rerender } = render();
// Initially loading
mockState.loading = true;
rerender();
// Then success
mockState.loading = false;
mockState.data = { ... };
rerender();
// Should not crash!
});
});
```
## When to Use
- When creating new screens in `frontend/src/screens/`
- When creating new components with state in `frontend/src/components/`
- When modifying existing components with hooks
- When creating custom hooks in `frontend/src/hooks/`
- During code review before merging PRs