Skip to main content

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)