React Quick Reference
Components
Functional Component
function MyComponent({ name }: { name: string }) {
return <div>Hello, {name}!</div>;
}
Component with Children
interface Props {
children: React.ReactNode;
}
function Container({ children }: Props) {
return <div className='container'>{children}</div>;
}
Hooks
useState
const [count, setCount] = useState(0);
const [user, setUser] = useState<User | null>(null);
// Functional update
setCount(prev => prev + 1);
useEffect
// Run once on mount
useEffect(() => {
fetchData();
}, []);
// Run when dependencies change
useEffect(() => {
console.log(count);
}, [count]);
// Cleanup
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer);
}, []);
useContext
const ThemeContext = createContext<'light' | 'dark'>('light');
function App() {
return (
<ThemeContext.Provider value='dark'>
<Child />
</ThemeContext.Provider>
);
}
function Child() {
const theme = useContext(ThemeContext);
return <div>{theme}</div>;
}
useReducer
type State = { count: number };
type Action = { type: 'increment' } | { type: 'decrement' };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
dispatch({ type: 'increment' });
useRef
const inputRef = useRef<HTMLInputElement>(null);
const countRef = useRef(0);
inputRef.current?.focus();
countRef.current += 1;
useMemo
const expensiveValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
useCallback
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
Custom Hook
function useLocalStorage\<T\>(key: string, initialValue: T) {
const [value, setValue] = useState\<T\>(() => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
Events
// Click
<button onClick={handleClick}>Click</button>
<button onClick={(e) => handleClick(e, id)}>Click</button>
// Form
<form onSubmit={handleSubmit}>
<input onChange={handleChange} />
</form>
// Mouse
<div onMouseEnter={handleEnter} onMouseLeave={handleLeave} />
// Keyboard
<input onKeyDown={handleKeyDown} onKeyUp={handleKeyUp} />
Conditional Rendering
// If/else
{
condition ? <ComponentA /> : <ComponentB />;
}
// Logical AND
{
condition && <Component />;
}
// Early return
if (!data) return <Loading />;
return <Content data={data} />;
// Nullish coalescing
{
value ?? 'default';
}
Lists
{
items.map(item => <div key={item.id}>{item.name}</div>);
}
Forms
function Form() {
const [email, setEmail] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Submit logic
};
return (
<form onSubmit={handleSubmit}>
<input
type='email'
value={email}
onChange={e => setEmail(e.target.value)}
/>
<button type='submit'>Submit</button>
</form>
);
}
TypeScript Types
// Props
interface ButtonProps {
text: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
}
// Event types
React.MouseEvent<HTMLButtonElement>;
React.ChangeEvent<HTMLInputElement>;
React.FormEvent<HTMLFormElement>;
React.KeyboardEvent<HTMLInputElement>;
// Children
React.ReactNode;
React.ReactElement;
React.FC<Props>;
// Refs
React.RefObject<HTMLDivElement>;
React.MutableRefObject<number>;
// Component type
React.ComponentType<Props>;
React.ElementType;
Performance Optimization
// Memo component
const MemoizedComponent = React.memo(Component);
// Memo with custom comparison
const MemoizedComponent = React.memo(Component, (prev, next) => {
return prev.id === next.id;
});
// Lazy loading
const LazyComponent = lazy(() => import('./Component'));
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>;
Error Boundary
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error(error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
React Router
import {
BrowserRouter,
Routes,
Route,
Link,
useNavigate,
useParams,
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
</nav>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/user/:id' element={<User />} />
</Routes>
</BrowserRouter>
);
}
function User() {
const { id } = useParams();
const navigate = useNavigate();
return <div>User {id}</div>;
}
Common Patterns
Compound Components
const Tabs = ({ children }) => <div>{children}</div>;
Tabs.List = ({ children }) => <div role='tablist'>{children}</div>;
Tabs.Tab = ({ children }) => <button>{children}</button>;
Tabs.Panel = ({ children }) => <div>{children}</div>;
<Tabs>
<Tabs.List>
<Tabs.Tab>Tab 1</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Content 1</Tabs.Panel>
</Tabs>;
Render Props
<DataFetcher
url='/api/users'
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>
HOC
function withAuth<P extends object>(Component: React.ComponentType<P>) {
return (props: P) => {
const user = useAuth();
if (!user) return <Login />;
return <Component {...props} />;
};
}
Best Practices
- ✅ Use functional components with hooks
- ✅ Use TypeScript for type safety
- ✅ Keep components small and focused
- ✅ Use proper keys in lists
- ✅ Avoid inline functions in JSX (use useCallback)
- ✅ Memoize expensive calculations (useMemo)
- ✅ Use fragments to avoid extra divs
- ✅ Handle loading and error states
- ✅ Clean up effects (return cleanup function)
- ✅ Use strict mode in development
Common Mistakes
- ❌ Missing keys in lists
- ❌ Using index as key when list changes
- ❌ Mutating state directly
- ❌ Missing dependencies in useEffect
- ❌ Infinite loops in useEffect
- ❌ Not cleaning up subscriptions
- ❌ Creating new objects/arrays in render
- ❌ Prop drilling (use Context instead)