React: Complete Guide and Cheat Sheet

    React: Complete Guide and Cheat Sheet

    04/11/2025

    Introduction

    React is the most popular library for building user interfaces. This guide covers modern React development, focusing on functional components, hooks, and the latest features introduced in React 18 and 19.

    1. Components

    Functional Components

    The standard way to write components in modern React.

    interface Props { name: string; age?: number; } export const Welcome: React.FC<Props> = ({ name, age }) => { return ( <div className="p-4 border rounded"> <h1>Hello, {name}</h1> {age && <p>Age: {age}</p>} </div> ); };

    JSX Rules

    • Return a single root element (or use Fragments <>...</>).
    • Use className instead of class.
    • Use htmlFor instead of for.
    • Close all tags (e.g., <br />).
    • CamelCase for attributes (e.g., onClick, tabIndex).

    2. Core Hooks

    useState

    Managing local state.

    const [count, setCount] = useState<number>(0); // Update based on previous state setCount(prev => prev + 1); // Object state const [user, setUser] = useState({ name: "John", age: 30 }); setUser(prev => ({ ...prev, name: "Jane" }));

    useEffect

    Handling side effects (fetching data, subscriptions, DOM manipulation).

    useEffect(() => { // Run on mount and when dependencies change const subscription = props.source.subscribe(); // Cleanup function (run on unmount or before re-running) return () => { subscription.unsubscribe(); }; }, [props.source]); // Dependency array

    useContext

    Consuming context values without prop drilling.

    const ThemeContext = createContext<"light" | "dark">("light"); const ThemedButton = () => { const theme = useContext(ThemeContext); return <button className={theme}>I am styled!</button>; };

    3. Additional Hooks

    useReducer

    For complex state logic or state transitions.

    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

    Accessing DOM elements or persisting values without re-renders.

    const inputRef = useRef<HTMLInputElement>(null); const focusInput = () => { inputRef.current?.focus(); }; // Persisting value const renderCount = useRef(0); useEffect(() => { renderCount.current++ });

    useMemo & useCallback

    Performance optimization hooks.

    // Memoize a value (only re-compute when dependencies change) const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); // Memoize a function (prevent re-creation on every render) const handleClick = useCallback(() => { console.log(a); }, [a]);

    useLayoutEffect

    Fires synchronously after all DOM mutations. Use for reading layout and re-rendering synchronously.

    useLayoutEffect(() => { const { height } = ref.current.getBoundingClientRect(); setHeight(height); }, []);

    useImperativeHandle

    Customizing the instance value that is exposed to parent components when using ref.

    useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); } }));

    useId

    Generating unique IDs for accessibility attributes.

    const id = useId(); return ( <> <label htmlFor={id}>Do you like React?</label> <input id={id} type="checkbox" name="react" /> </> );

    useDebugValue

    Displaying a label for custom hooks in React DevTools.

    useDebugValue(isOnline ? 'Online' : 'Offline');

    useSyncExternalStore

    Subscribing to an external store.

    const state = useSyncExternalStore(store.subscribe, store.getSnapshot);

    useInsertionEffect

    Fires before any DOM mutations. Intended for CSS-in-JS libraries to inject styles.

    useInsertionEffect(() => { const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); }, [css]);

    4. React 18/19 Features

    Server Components (RSC)

    Components that run exclusively on the server. They have zero bundle size impact and can access the database directly.

    // app/page.tsx (Server Component by default in Next.js App Router) import db from './db'; export default async function Page() { const data = await db.query('SELECT * FROM posts'); return ( <ul> {data.map(post => ( <li key={post.id}>{post.title}</li> ))} </ul> ); }

    Server Actions

    Functions that run on the server, callable from Client Components.

    // actions.ts 'use server' export async function createPost(formData: FormData) { const title = formData.get('title'); await db.post.create({ data: { title } }); } // Component.tsx import { createPost } from './actions'; export function Form() { return ( <form action={createPost}> <input name="title" /> <button type="submit">Create</button> </form> ); }

    useTransition

    Marking state updates as non-blocking transitions.

    const [isPending, startTransition] = useTransition(); const handleChange = (e) => { const value = e.target.value; // Urgent update: Show input immediately setInputValue(value); startTransition(() => { // Non-urgent update: Filter list (can be interrupted) setSearchQuery(value); }); };

    useDeferredValue

    Deferring a value update to keep the UI responsive.

    const deferredQuery = useDeferredValue(query); // Pass deferredQuery to heavy list component

    useActionState (React 19)

    Managing state for server actions (formerly useFormState).

    import { useActionState } from 'react'; import { updateName } from './actions'; function ChangeName() { const [state, action, isPending] = useActionState(updateName, { error: null }); return ( <form action={action}> <input type="text" name="name" /> <button type="submit" disabled={isPending}>Update</button> {state.error && <p>{state.error}</p>} </form> ); }

    useFormStatus (React 19)

    Accessing the status of a parent <form> without prop drilling.

    import { useFormStatus } from 'react-dom'; function SubmitButton() { const { pending } = useFormStatus(); return <button disabled={pending}>{pending ? 'Submitting...' : 'Submit'}</button>; }

    useOptimistic (React 19)

    Optimistically updating UI while an async action is pending.

    import { useOptimistic } from 'react'; function Thread({ messages, sendMessage }) { const [optimisticMessages, addOptimisticMessage] = useOptimistic( messages, (state, newMessage) => [...state, newMessage] ); async function formAction(formData) { const message = formData.get("message"); addOptimisticMessage(message); // Update UI immediately await sendMessage(message); // Perform actual server action } return ( // ... render optimisticMessages ); }

    The use Hook (React 19)

    Reading resources (Promises or Context) in render.

    import { use } from 'react'; function Comments({ commentsPromise }) { // Suspends until promise resolves const comments = use(commentsPromise); return comments.map(c => <p key={c.id}>{c.text}</p>); }

    Document Metadata (React 19)

    Native support for rendering <title>, <meta>, and <link> tags anywhere in the component tree.

    function BlogPost({ title }) { return ( <article> <title>{title}</title> <meta name="description" content="This is a blog post" /> <h1>{title}</h1> </article> ); }

    5. Performance

    React.memo

    Prevents re-rendering a component if props haven't changed.

    const MyComponent = React.memo(function MyComponent(props) { /* render using props */ });

    Lazy Loading & Suspense

    Code-splitting components.

    const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); }

    6. Advanced Patterns

    Custom Hooks

    Extracting component logic into reusable functions.

    function useWindowSize() { const [size, setSize] = useState({ width: 0, height: 0 }); useEffect(() => { function updateSize() { setSize({ width: window.innerWidth, height: window.innerHeight }); } window.addEventListener('resize', updateSize); updateSize(); return () => window.removeEventListener('resize', updateSize); }, []); return size; }

    Error Boundaries

    Catching JavaScript errors in child component tree.

    class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean}> { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { logErrorToMyService(error, errorInfo); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } }

    Portals

    Rendering children into a DOM node that exists outside the DOM hierarchy of the parent component.

    import { createPortal } from 'react-dom'; function Modal({ children }) { return createPortal( children, document.getElementById('modal-root')! ); }

    7. TypeScript Integration

    Typing Props

    type ButtonProps = { children: React.ReactNode; onClick: (event: React.MouseEvent<HTMLButtonElement>) => void; variant?: 'primary' | 'secondary'; style?: React.CSSProperties; };

    Typing Events

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { console.log(e.target.value); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); };

    forwardRef (Deprecated in React 19)

    In React 19, ref is passed as a normal prop, so forwardRef is no longer needed for function components.

    // React 19+ function MyInput({ placeholder, ref }) { return <input placeholder={placeholder} ref={ref} />; } // Usage <MyInput ref={inputRef} />

    Typing Props

    Summarise

    Transform Your Learning

    Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.

    Instant video summaries
    Smart insights extraction
    Channel tracking