| name | react-dev-helper |
|---|---|
| description | This skill assists with React + TypeScript project development by providing project standards, coding guidelines, and common workflows. Use this skill when working on React projects to ensure code quality, maintain consistent style, follow best practices, and execute common development tasks correctly. The skill emphasizes test-first development and ESLint compliance. |
Assist with React + TypeScript project development by providing coding standards, development workflows, and best practices. Ensure all code follows project conventions and passes quality checks before committing.
- Framework: React with TypeScript
- Language Features: ES6+ syntax
- Component Style: Functional components (prefer over class components)
- Naming Convention: camelCase for variables and functions
Before any code modification or commit:
- ✅ Run tests to ensure existing functionality works
- ✅ Check for ESLint errors and warnings
- ✅ Verify TypeScript types are correct
- ✅ Ensure code follows project style guidelines
Follow this workflow for all development tasks:
Run Tests First:
npm testVerify all existing tests pass before making changes. This establishes a baseline.
Check Current Code Quality:
npm run lint
# or if ESLint is configured separately
npx eslint .Component Development Guidelines:
- Use functional components with hooks
- Extract reusable logic into custom hooks
- Keep components small and focused (single responsibility)
- Use TypeScript interfaces for props and state
Example Good Component:
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
const Button: React.FC<ButtonProps> = ({ label, onClick, disabled = false }) => {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
);
};
export default Button;Naming Conventions:
- Variables and functions:
camelCase - Components:
PascalCase - Constants:
UPPER_SNAKE_CASE - Private functions: prefix with underscore
_privateFunction - Boolean variables: prefix with
is,has,should(e.g.,isLoading,hasError)
Import Organization:
// 1. External libraries
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
// 2. Internal components
import Button from './components/Button';
import Header from './components/Header';
// 3. Utilities and helpers
import { formatDate } from './utils/dateUtils';
import { API_BASE_URL } from './constants';
// 4. Types
import type { User, Post } from './types';
// 5. Styles
import './App.css';Pre-Commit Checklist:
Run this sequence before every commit:
-
Run all tests:
npm testAll tests must pass. If any fail, fix them before proceeding.
-
Check ESLint:
npm run lint # Fix any errors npm run lint -- --fix # Auto-fix where possible
No ESLint errors should remain.
-
Type check:
npx tsc --noEmit
Verify no TypeScript errors.
-
Build verification (optional but recommended):
npm run build
Ensure production build succeeds.
| Command | Purpose | When to Use |
|---|---|---|
npm run dev |
Start development server | Beginning development session |
npm test |
Run test suite | Before changes, during development, before commit |
npm run build |
Build for production | Before deployment, verify build works |
npm run lint |
Check code style | Before commit |
npm run lint -- --fix |
Auto-fix lint issues | Fix formatting issues |
npm install <package> |
Add new dependency | Adding new library |
npm install --save-dev <package> |
Add dev dependency | Adding development tool |
# Run all tests
npm test
# Run tests in watch mode
npm test -- --watch
# Run tests with coverage
npm test -- --coverage
# Run specific test file
npm test -- ComponentName.test.tsxPrefer:
- Arrow functions for callbacks
- Destructuring for props and objects
- Template literals for string interpolation
- Spread operator for object/array operations
- Optional chaining (
?.) and nullish coalescing (??) constandlet(nevervar)
Example:
// Good
const UserProfile = ({ user, onUpdate }) => {
const { name, email, avatar } = user;
const displayName = name ?? 'Anonymous';
return (
<div>
<img src={avatar} alt={`${displayName}'s avatar`} />
<p>{displayName}</p>
<p>{email?.toLowerCase()}</p>
</div>
);
};
// Avoid
var UserProfile = function(props) {
var name = props.user.name;
var email = props.user.email;
// ...
};State Management:
// Use useState for local state
const [count, setCount] = useState<number>(0);
// Use useReducer for complex state
const [state, dispatch] = useReducer(reducer, initialState);
// Use custom hooks for reusable logic
const { data, loading, error } = useFetchData(url);Side Effects:
// Use useEffect for side effects
useEffect(() => {
// Effect logic
return () => {
// Cleanup
};
}, [dependencies]);Memoization:
// Memoize expensive calculations
const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
// Memoize callback functions
const handleClick = useCallback(() => {
doSomething(a, b);
}, [a, b]);Props Interface:
// Define clear prop types
interface UserCardProps {
user: User;
showAvatar?: boolean;
onEdit?: (userId: string) => void;
}
// Use the interface
const UserCard: React.FC<UserCardProps> = ({ user, showAvatar = true, onEdit }) => {
// Component implementation
};State Types:
// Type your state
interface FormState {
username: string;
email: string;
errors: Record<string, string>;
}
const [formState, setFormState] = useState<FormState>({
username: '',
email: '',
errors: {}
});Avoid any:
// Bad
const data: any = fetchData();
// Good
interface ApiResponse {
data: User[];
status: number;
}
const response: ApiResponse = fetchData();- All components with logic
- Utility functions
- Custom hooks
- API interactions
- Complex state management
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
describe('Button Component', () => {
it('renders with correct label', () => {
render(<Button label="Click me" onClick={() => {}} />);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button label="Click" onClick={handleClick} />);
fireEvent.click(screen.getByText('Click'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('is disabled when disabled prop is true', () => {
render(<Button label="Click" onClick={() => {}} disabled />);
expect(screen.getByRole('button')).toBeDisabled();
});
});"React must be in scope" (older React versions)
// Add import even if not directly used
import React from 'react';"Missing key prop"
// Always add key when mapping
{items.map(item => <div key={item.id}>{item.name}</div>)}"Missing dependency in useEffect"
// Add all dependencies or use ESLint disable if intentional
useEffect(() => {
fetchData(userId);
}, [userId]); // Include all used variables"Property does not exist on type"
// Define proper interface
interface User {
id: string;
name: string;
email?: string; // Optional property
}Before starting any new feature or bug fix:
- Pull latest changes from main branch
- Run
npm installto ensure dependencies are up to date - Run
npm testto verify all tests pass - Run
npm run lintto check for existing issues - Understand the task requirements clearly
- Plan component structure if building new features
Before committing code:
- All tests pass (
npm test) - No ESLint errors (
npm run lint) - No TypeScript errors (
npx tsc --noEmit) - Code follows naming conventions
- Components are functional (not class-based)
- Proper TypeScript types are defined
- New functionality has tests
- Console logs removed (except intentional logging)
- Comments explain "why", not "what"
- Build succeeds (
npm run build)
react-patterns.md- Common React patterns and anti-patterns referencetypescript-guide.md- TypeScript specific guidelines for React developmenttesting-guide.md- Comprehensive testing strategies and examples