| name | react-debugging |
| description | Debug React components, fix hooks errors, resolve TypeScript issues, handle state management bugs, and fix rendering problems. Use when encountering React errors, hooks violations, type errors, or component rendering issues. |
| allowed-tools | Read, Edit, Grep, Glob, Bash |
React Component Debugging
Expert assistance for debugging React components and hooks in the MantisNXT Next.js project.
Capabilities
- Component Error Debugging: Fix runtime errors in React components
- Hooks Troubleshooting: Resolve issues with useState, useEffect, useQuery, etc.
- TypeScript Error Resolution: Fix type mismatches and inference issues
- State Management: Debug Zustand stores and React Query caches
- Rendering Issues: Fix hydration errors, infinite loops, and performance problems
Common Errors & Solutions
"X.map is not a function"
Cause: Variable expected to be an array is not an array (undefined, null, or object)
Solution:
// ❌ Unsafe
const items = data;
items.map(item => ...)
// ✅ Safe - ensure it's always an array
const items = Array.isArray(data) ? data : [];
items.map(item => ...)
// ✅ Alternative - provide default
const items = data || [];
const items = data ?? [];
"Cannot read property 'X' of undefined"
Cause: Accessing property on undefined/null object
Solution:
// ❌ Unsafe
const name = user.profile.name;
// ✅ Optional chaining
const name = user?.profile?.name;
// ✅ With default
const name = user?.profile?.name ?? 'Unknown';
"Rendered more hooks than during previous render"
Cause: Conditional hooks usage violates Rules of Hooks
Solution:
// ❌ Wrong - conditional hook
if (condition) {
const [state, setState] = useState(0);
}
// ✅ Correct - hook always called
const [state, setState] = useState(0);
if (condition) {
// use state here
}
"Hydration failed"
Cause: Server-rendered HTML doesn't match client render
Solution:
// ❌ Causes hydration mismatch
<div>{Math.random()}</div>
// ✅ Use client-only rendering
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
// ✅ Or mark component as client-side
'use client'
"Maximum update depth exceeded"
Cause: Infinite loop in useEffect or state updates
Solution:
// ❌ Wrong - infinite loop
useEffect(() => {
setState(newValue); // triggers re-render → triggers effect again
});
// ✅ Correct - proper dependencies
useEffect(() => {
setState(newValue);
}, [dependency]); // only runs when dependency changes
React Query Issues
Stale Data
// Force refetch
const { data, refetch } = useQuery(...);
refetch();
// Invalidate cache
queryClient.invalidateQueries(['key']);
// Set stale time
useQuery(['key'], fetcher, {
staleTime: 5 * 60 * 1000, // 5 minutes
});
Loading States
const { data, isLoading, error } = useQuery(...);
// ✅ Handle all states
if (isLoading) return <Loading />;
if (error) return <Error error={error} />;
if (!data) return <Empty />;
return <Content data={data} />;
Component File Locations
src/
├── components/
│ ├── dashboard/ # Dashboard components
│ ├── suppliers/ # Supplier management
│ ├── spp/ # Supplier pricelist processing
│ ├── layout/ # Layout components
│ └── ui/ # Shadcn UI components
├── hooks/
│ └── useNeonSpp.ts # React Query hooks
└── lib/
├── stores/ # Zustand stores
└── services/ # API services
Debugging Workflow
- Read the error message carefully - it often tells you exactly what's wrong
- Check the stack trace to find the exact line causing the issue
- Inspect the component where the error occurs
- Verify data types - ensure variables are what you expect (array vs object vs null)
- Check dependencies - verify useEffect/useCallback dependencies are correct
- Add console.logs strategically to track data flow
- Test incrementally - fix one issue at a time
Type Safety Best Practices
// ✅ Define proper interfaces
interface Upload {
upload_id: string;
filename: string;
status: string;
row_count: number;
}
// ✅ Type hook data
const { data } = useQuery<Upload[]>(...);
// ✅ Ensure array type
const uploads = Array.isArray(data) ? data : [];
// ✅ Type props
interface Props {
uploads: Upload[];
onRefresh: () => void;
}
Common Hook Patterns
Safe Data Fetching
const { data, isLoading, error } = useQuery(
['key'],
fetchFn,
{
staleTime: 5 * 60 * 1000,
retry: 3,
onError: (err) => console.error(err)
}
);
// Safely handle data
const items = Array.isArray(data) ? data : [];
Conditional Effects
useEffect(() => {
if (!condition) return; // early exit
// effect logic
return () => {
// cleanup
};
}, [condition]);
Memoization
// Expensive computation
const result = useMemo(() => {
return expensiveOperation(data);
}, [data]);
// Callback stability
const handleClick = useCallback(() => {
doSomething(value);
}, [value]);
Performance Optimization
- Use
React.memofor expensive components - Implement virtualization for long lists (react-window)
- Lazy load heavy components with
React.lazy - Debounce search inputs
- Optimize re-renders with proper dependency arrays
Testing Components
// Check component renders without errors
npm run dev
// Visit page in browser
// Type checking
npm run type-check
// Build check (catches many issues)
npm run build
Best Practices
- Always handle loading and error states
- Ensure data is the expected type before using array/object methods
- Follow Rules of Hooks - call hooks at top level, consistently
- Use TypeScript properly - don't use
any, define proper types - Add null checks for optional data
- Use optional chaining (?.) and nullish coalescing (??)
- Test edge cases - empty arrays, null values, loading states
- Keep components focused - single responsibility
- Extract custom hooks for reusable logic
- Clean up effects - return cleanup functions