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.
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> ); };
<>...</>).className instead of class.htmlFor instead of for.<br />).onClick, tabIndex).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" }));
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
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>; };
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" });
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++ });
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]);
Fires synchronously after all DOM mutations. Use for reading layout and re-rendering synchronously.
useLayoutEffect(() => { const { height } = ref.current.getBoundingClientRect(); setHeight(height); }, []);
Customizing the instance value that is exposed to parent components when using ref.
useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); } }));
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" /> </> );
Displaying a label for custom hooks in React DevTools.
useDebugValue(isOnline ? 'Online' : 'Offline');
Subscribing to an external store.
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
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]);
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> ); }
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> ); }
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); }); };
Deferring a value update to keep the UI responsive.
const deferredQuery = useDeferredValue(query); // Pass deferredQuery to heavy list component
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> ); }
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>; }
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 ); }
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>); }
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> ); }
Prevents re-rendering a component if props haven't changed.
const MyComponent = React.memo(function MyComponent(props) { /* render using props */ });
Code-splitting components.
const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); }
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; }
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; } }
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')! ); }
type ButtonProps = { children: React.ReactNode; onClick: (event: React.MouseEvent<HTMLButtonElement>) => void; variant?: 'primary' | 'secondary'; style?: React.CSSProperties; };
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { console.log(e.target.value); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); };
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} />
Comprehensive guide to TypeScript with practical examples and best practices. Learn how to effectively use TypeScript in modern web applications.
Master JavaScript Arrays with this practical guide. Learn how to transform, filter, group, and process data efficiently through real-world examples, from basic operations to the latest features.

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