- Spec files
npm-react
Describes: pkg:npm/react@19.1.x
- Description
- React is a JavaScript library for building user interfaces with a declarative, component-based approach.
- Author
- tessl
- Last updated
hooks.md docs/
1# Hooks23React Hooks for state management, side effects, and component lifecycle in function components. Hooks allow you to use state and other React features without writing a class component.45## Capabilities67### useState89Hook for managing local component state in function components.1011```typescript { .api }12/**13* Adds state to function components14* @param initialState - Initial state value or function returning initial state15* @returns Array with current state and state setter function16*/17function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>];1819type SetStateAction<S> = S | ((prevState: S) => S);20type Dispatch<A> = (value: A) => void;21```2223**Usage Examples:**2425```typescript26import React, { useState } from "react";2728function Counter() {29const [count, setCount] = useState(0);30const [name, setName] = useState(() => "Initial Name");3132return (33<div>34<p>Count: {count}</p>35<button onClick={() => setCount(count + 1)}>Increment</button>36<button onClick={() => setCount(prev => prev + 1)}>Increment (functional)</button>3738<input39value={name}40onChange={e => setName(e.target.value)}41/>42</div>43);44}45```4647### useEffect4849Hook for performing side effects in function components (data fetching, subscriptions, DOM manipulation).5051```typescript { .api }52/**53* Performs side effects in function components54* @param effect - Function containing side effect logic55* @param deps - Optional dependency array controlling when effect runs56*/57function useEffect(58effect: React.EffectCallback,59deps?: React.DependencyList60): void;6162type EffectCallback = () => (void | (() => void | undefined));63type DependencyList = ReadonlyArray<any>;64```6566**Usage Examples:**6768```typescript69import React, { useState, useEffect } from "react";7071function UserProfile({ userId }: { userId: string }) {72const [user, setUser] = useState(null);73const [loading, setLoading] = useState(true);7475// Effect with cleanup76useEffect(() => {77let cancelled = false;7879async function fetchUser() {80try {81const response = await fetch(`/api/users/${userId}`);82const userData = await response.json();8384if (!cancelled) {85setUser(userData);86setLoading(false);87}88} catch (error) {89if (!cancelled) {90console.error("Failed to fetch user:", error);91setLoading(false);92}93}94}9596fetchUser();9798// Cleanup function99return () => {100cancelled = true;101};102}, [userId]); // Effect runs when userId changes103104// Effect without dependencies (runs on every render)105useEffect(() => {106document.title = user ? `Profile: ${user.name}` : "Loading...";107});108109if (loading) return <div>Loading...</div>;110return <div>User: {user?.name}</div>;111}112```113114### useContext115116Hook for consuming React context values.117118```typescript { .api }119/**120* Consumes context value from the nearest Provider121* @param context - React context object created with createContext122* @returns Current context value123*/124function useContext<T>(context: React.Context<T>): T;125```126127**Usage Examples:**128129```typescript130import React, { useContext, createContext } from "react";131132const ThemeContext = createContext<{ theme: string; toggleTheme: () => void }>({133theme: "light",134toggleTheme: () => {}135});136137function ThemeButton() {138const { theme, toggleTheme } = useContext(ThemeContext);139140return (141<button onClick={toggleTheme}>142Current theme: {theme}143</button>144);145}146```147148### useReducer149150Hook for state management using the reducer pattern, ideal for complex state logic.151152```typescript { .api }153/**154* Manages state with a reducer function155* @param reducer - Function that takes current state and action, returns new state156* @param initialState - Initial state value157* @param initializer - Optional function to lazily initialize state158* @returns Array with current state and dispatch function159*/160function useReducer<R extends React.Reducer<any, any>>(161reducer: R,162initialState: React.ReducerState<R>,163initializer?: undefined164): [React.ReducerState<R>, React.Dispatch<React.ReducerAction<R>>];165166function useReducer<R extends React.Reducer<any, any>, I>(167reducer: R,168initialArg: I,169initializer: (arg: I) => React.ReducerState<R>170): [React.ReducerState<R>, React.Dispatch<React.ReducerAction<R>>];171172type Reducer<S, A> = (prevState: S, action: A) => S;173```174175**Usage Examples:**176177```typescript178import React, { useReducer } from "react";179180interface State {181count: number;182error: string | null;183}184185type Action =186| { type: "increment" }187| { type: "decrement" }188| { type: "reset" }189| { type: "error"; message: string };190191function counterReducer(state: State, action: Action): State {192switch (action.type) {193case "increment":194return { ...state, count: state.count + 1, error: null };195case "decrement":196return { ...state, count: state.count - 1, error: null };197case "reset":198return { ...state, count: 0, error: null };199case "error":200return { ...state, error: action.message };201default:202return state;203}204}205206function Counter() {207const [state, dispatch] = useReducer(counterReducer, { count: 0, error: null });208209return (210<div>211<p>Count: {state.count}</p>212{state.error && <p>Error: {state.error}</p>}213<button onClick={() => dispatch({ type: "increment" })}>+</button>214<button onClick={() => dispatch({ type: "decrement" })}>-</button>215<button onClick={() => dispatch({ type: "reset" })}>Reset</button>216</div>217);218}219```220221### useRef222223Hook for creating mutable ref objects that persist across re-renders.224225```typescript { .api }226/**227* Creates a mutable ref object228* @param initialValue - Initial value for the ref229* @returns Mutable ref object with current property230*/231function useRef<T = undefined>(): React.MutableRefObject<T | undefined>;232function useRef<T = undefined>(initialValue: T): React.MutableRefObject<T>;233function useRef<T>(initialValue: T | null): React.RefObject<T>;234235interface MutableRefObject<T> {236current: T;237}238239interface RefObject<T> {240readonly current: T | null;241}242```243244**Usage Examples:**245246```typescript247import React, { useRef, useEffect } from "react";248249function TextInput() {250const inputRef = useRef<HTMLInputElement>(null);251const renderCount = useRef(0);252253useEffect(() => {254renderCount.current += 1;255});256257const focusInput = () => {258inputRef.current?.focus();259};260261return (262<div>263<input ref={inputRef} type="text" />264<button onClick={focusInput}>Focus Input</button>265<p>Render count: {renderCount.current}</p>266</div>267);268}269```270271### useLayoutEffect272273Hook for synchronous side effects that run before the browser paints.274275```typescript { .api }276/**277* Runs effect synchronously before browser paint278* @param effect - Function containing side effect logic279* @param deps - Optional dependency array controlling when effect runs280*/281function useLayoutEffect(282effect: React.EffectCallback,283deps?: React.DependencyList284): void;285```286287**Usage Examples:**288289```typescript290import React, { useLayoutEffect, useRef, useState } from "react";291292function MeasureComponent() {293const divRef = useRef<HTMLDivElement>(null);294const [height, setHeight] = useState(0);295296useLayoutEffect(() => {297if (divRef.current) {298setHeight(divRef.current.offsetHeight);299}300});301302return (303<div>304<div ref={divRef} style={{ padding: "20px", border: "1px solid black" }}>305This div's height is {height}px306</div>307</div>308);309}310```311312### useInsertionEffect313314Hook designed for CSS-in-JS libraries to inject styles before layout effects run.315316```typescript { .api }317/**318* Runs effect before all DOM mutations (for CSS-in-JS libraries)319* @param effect - Function containing side effect logic320* @param deps - Optional dependency array controlling when effect runs321*/322function useInsertionEffect(323effect: React.EffectCallback,324deps?: React.DependencyList325): void;326```327328### useImperativeHandle329330Hook for customizing the instance value exposed by a ref when using forwardRef.331332```typescript { .api }333/**334* Customizes ref instance value exposed to parent components335* @param ref - Ref object from forwardRef336* @param createHandle - Function returning the handle object337* @param deps - Optional dependency array338*/339function useImperativeHandle<T, R extends T>(340ref: React.Ref<T> | undefined,341createHandle: () => R,342deps?: React.DependencyList343): void;344```345346**Usage Examples:**347348```typescript349import React, { useImperativeHandle, useRef, forwardRef } from "react";350351interface InputHandle {352focus: () => void;353setValue: (value: string) => void;354}355356const FancyInput = forwardRef<InputHandle, { placeholder?: string }>((props, ref) => {357const inputRef = useRef<HTMLInputElement>(null);358359useImperativeHandle(ref, () => ({360focus: () => {361inputRef.current?.focus();362},363setValue: (value: string) => {364if (inputRef.current) {365inputRef.current.value = value;366}367}368}));369370return <input ref={inputRef} placeholder={props.placeholder} />;371});372373function Parent() {374const inputRef = useRef<InputHandle>(null);375376return (377<div>378<FancyInput ref={inputRef} placeholder="Enter text" />379<button onClick={() => inputRef.current?.focus()}>Focus</button>380<button onClick={() => inputRef.current?.setValue("Hello!")}>Set Value</button>381</div>382);383}384```385386### useDebugValue387388Hook for displaying debug information in React DevTools for custom hooks.389390```typescript { .api }391/**392* Displays debug value in React DevTools393* @param value - Value to display394* @param format - Optional formatter function395*/396function useDebugValue<T>(397value: T,398format?: (value: T) => any399): void;400```401402**Usage Examples:**403404```typescript405import React, { useState, useDebugValue } from "react";406407function useCounter(initialValue: number = 0) {408const [count, setCount] = useState(initialValue);409410// Shows "Counter: 5" in React DevTools411useDebugValue(count, count => `Counter: ${count}`);412413const increment = () => setCount(c => c + 1);414const decrement = () => setCount(c => c - 1);415416return { count, increment, decrement };417}418```419420### useId421422Hook for generating unique IDs that are consistent between server and client.423424```typescript { .api }425/**426* Generates unique ID for accessibility attributes427* @returns Unique string ID428*/429function useId(): string;430```431432**Usage Examples:**433434```typescript435import React, { useId } from "react";436437function PasswordField() {438const passwordHintId = useId();439440return (441<div>442<label>443Password:444<input445type="password"446aria-describedby={passwordHintId}447/>448</label>449<div id={passwordHintId}>450Password should contain at least 8 characters451</div>452</div>453);454}455```456457### useActionState458459Hook for managing form actions and pending states.460461```typescript { .api }462/**463* Manages form action state and pending status464* @param action - Action function to execute465* @param initialState - Initial state value466* @param permalink - Optional permalink for the action467* @returns Array with current state, action function, and pending status468*/469function useActionState<S, P>(470action: (state: S, payload: P) => S | Promise<S>,471initialState: S,472permalink?: string473): [state: S, formAction: (payload: P) => void, isPending: boolean];474```475476**Usage Examples:**477478```typescript479import React, { useActionState } from "react";480481async function updateName(currentState: { name: string; error?: string }, formData: FormData) {482const name = formData.get("name") as string;483484if (!name) {485return { name: currentState.name, error: "Name is required" };486}487488// Simulate API call489await new Promise(resolve => setTimeout(resolve, 1000));490491return { name, error: undefined };492}493494function NameForm() {495const [state, formAction, isPending] = useActionState(updateName, { name: "" });496497return (498<form action={formAction}>499<input500name="name"501defaultValue={state.name}502disabled={isPending}503/>504<button type="submit" disabled={isPending}>505{isPending ? "Updating..." : "Update"}506</button>507{state.error && <p style={{ color: "red" }}>{state.error}</p>}508</form>509);510}511```512513### experimental_useEffectEvent514515Experimental hook that creates event handlers that don't re-run effects when their dependencies change.516517```typescript { .api }518/**519* Creates an event handler that can access current values without causing effect re-runs520* @param callback - The event handler function521* @returns A stable event handler function522*/523function experimental_useEffectEvent<Args extends any[], Return>(524callback: (...args: Args) => Return525): (...args: Args) => Return;526```527528**Usage Examples:**529530```typescript531import React, { useState, useEffect, experimental_useEffectEvent } from "react";532533function Chat({ roomId }: { roomId: string }) {534const [message, setMessage] = useState("");535const [connection, setConnection] = useState<any>(null);536537// Event handler that can access current state without re-subscribing538const onReceiveMessage = experimental_useEffectEvent((receivedMessage: string) => {539console.log("Received:", receivedMessage, "Current message:", message);540});541542useEffect(() => {543const conn = createConnection(roomId);544conn.on("message", onReceiveMessage);545setConnection(conn);546conn.connect();547548return () => {549conn.disconnect();550};551}, [roomId]); // Only re-run when roomId changes, not when message changes552553return (554<div>555<input556value={message}557onChange={e => setMessage(e.target.value)}558placeholder="Type a message..."559/>560</div>561);562}563```564565### useSyncExternalStore566567Hook for subscribing to external data sources with support for server-side rendering and concurrent features.568569```typescript { .api }570/**571* Subscribes to an external store and returns its current value572* @param subscribe - Function that subscribes to store changes573* @param getSnapshot - Function that returns the current store value574* @param getServerSnapshot - Optional function for server-side rendering575* @returns Current store value576*/577function useSyncExternalStore<Snapshot>(578subscribe: (onStoreChange: () => void) => () => void,579getSnapshot: () => Snapshot,580getServerSnapshot?: () => Snapshot581): Snapshot;582```583584**Usage Examples:**585586```typescript587import React, { useSyncExternalStore } from "react";588589// Example: Browser online status store590const onlineStore = {591subscribe(callback: () => void) {592window.addEventListener("online", callback);593window.addEventListener("offline", callback);594return () => {595window.removeEventListener("online", callback);596window.removeEventListener("offline", callback);597};598},599getSnapshot() {600return navigator.onLine;601},602getServerSnapshot() {603return true; // Assume online on server604}605};606607function OnlineStatus() {608const isOnline = useSyncExternalStore(609onlineStore.subscribe,610onlineStore.getSnapshot,611onlineStore.getServerSnapshot612);613614return <div>Status: {isOnline ? "Online" : "Offline"}</div>;615}616617// Example: Custom store618class CounterStore {619private count = 0;620private listeners = new Set<() => void>();621622subscribe = (callback: () => void) => {623this.listeners.add(callback);624return () => this.listeners.delete(callback);625};626627getSnapshot = () => this.count;628629increment = () => {630this.count++;631this.listeners.forEach(callback => callback());632};633}634635const counterStore = new CounterStore();636637function Counter() {638const count = useSyncExternalStore(639counterStore.subscribe,640counterStore.getSnapshot641);642643return (644<div>645<p>Count: {count}</p>646<button onClick={counterStore.increment}>Increment</button>647</div>648);649}650```651652### use653654Hook for consuming promises and context that can be used conditionally, unlike other hooks.655656```typescript { .api }657/**658* Consumes a Promise or Context value659* @param usable - A Promise or React Context to consume660* @returns The resolved value of the Promise or the Context value661*/662function use<T>(usable: Promise<T>): T;663function use<T>(usable: React.Context<T>): T;664```665666**Usage Examples:**667668```typescript669import React, { use, createContext, Suspense } from "react";670671// Example 1: Using with Context672const ThemeContext = createContext("light");673674function Button() {675const theme = use(ThemeContext);676677return (678<button className={`button-${theme}`}>679Themed Button680</button>681);682}683684// Example 2: Using with Promises685async function fetchUser(id: string) {686const response = await fetch(`/api/users/${id}`);687return response.json();688}689690function UserProfile({ userId }: { userId: string }) {691// This can be conditional, unlike other hooks692if (!userId) {693return <div>No user selected</div>;694}695696const userPromise = fetchUser(userId);697const user = use(userPromise); // Suspends until promise resolves698699return (700<div>701<h1>{user.name}</h1>702<p>{user.email}</p>703</div>704);705}706707function App() {708const [userId, setUserId] = React.useState<string>("");709710return (711<Suspense fallback={<div>Loading user...</div>}>712<input713value={userId}714onChange={e => setUserId(e.target.value)}715placeholder="Enter user ID"716/>717<UserProfile userId={userId} />718</Suspense>719);720}721```722723## Types724725### Hook-Related Types726727```typescript { .api }728type EffectCallback = () => (void | (() => void | undefined));729type DependencyList = ReadonlyArray<any>;730731type SetStateAction<S> = S | ((prevState: S) => S);732type Dispatch<A> = (value: A) => void;733734type Reducer<S, A> = (prevState: S, action: A) => S;735type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;736type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;737738type MutableRefObject<T> = {739current: T;740};741742type RefObject<T> = {743readonly current: T | null;744};745```