React 19 Hooks & Patterns Reference
A comprehensive, copy-paste ready reference for React 19's new features. Discover how to use Server Components, the 'use' hook, form actions, and transition enhancements to build modern React applications.
use() Hook
New HooksRead the value of a resource like a Promise or context directly in render.
View Official Docsimport { use, Suspense } from "react";
const fetchMessage = async (): Promise<string> => {
const res = await fetch('/api/message');
return res.text();
};
const messagePromise = fetchMessage();
function Message() {
// use() suspends the component until the promise resolves
const message = use(messagePromise);
return <p>{message}</p>;
}
export default function App() {
return (
<Suspense fallback={<p>Downloading message...</p>}>
<Message />
</Suspense>
);
}useOptimistic
New HooksOptimistically update UI while a background operation (like a mutation) is pending.
View Official Docsimport { useOptimistic, useRef } from "react";
type Message = { text: string; sending: boolean };
export function ChatMessages({ messages, sendMessage }: { messages: Message[], sendMessage: (formData: FormData) => Promise<void> }) {
const formRef = useRef<HTMLFormElement>(null);
const [optimisticMessages, addOptimisticMessage] = useOptimistic<Message[], string>(
messages,
(state, newMessage) => [...state, { text: newMessage, sending: true }]
);
async function formAction(formData: FormData) {
addOptimisticMessage(formData.get("message") as string);
formRef.current?.reset();
await sendMessage(formData);
}
return (
<div>
{optimisticMessages.map((m, i) => (
<div key={i}>{m.text} {m.sending && <small>(Sending...)</small>}</div>
))}
<form action={formAction} ref={formRef}>
<input type="text" name="message" required />
<button type="submit">Send</button>
</form>
</div>
);
}useFormStatus
Form HooksGet status information of the parent <form> without passing props. Must be called in a child component of the form.
View Official Docsimport { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending, data, method, action } = useFormStatus();
return (
<button type="submit" disabled={pending} className="bg-blue-500 text-white p-2">
{pending ? "Submitting..." : "Submit"}
</button>
);
}
export function PostForm({ createPost }: { createPost: (data: FormData) => Promise<void> }) {
return (
<form action={createPost}>
<input type="text" name="title" required />
<SubmitButton />
</form>
);
}useActionState
Form HooksManage state related to a form action (formerly useFormState). Great for validation errors and returned data.
View Official Docsimport { useActionState } from "react";
async function incrementAction(previousState: number, formData: FormData): Promise<number> {
const incrementBy = Number(formData.get("amount") || 1);
return previousState + incrementBy;
}
export function Counter() {
const [state, formAction, isPending] = useActionState<number, FormData>(incrementAction, 0);
return (
<form action={formAction}>
<p>Count: {state}</p>
<input type="number" name="amount" defaultValue="1" />
<button type="submit" disabled={isPending}>
{isPending ? "Incrementing..." : "Increment"}
</button>
</form>
);
}useTransition (Async Support)
Suspense & TransitionsIn React 19, startTransition can now take an async function, allowing you to wait for transitions to complete.
View Official Docsimport { useState, useTransition } from "react";
import { updateName } from "./actions";
export function ProfileForm() {
const [name, setName] = useState<string>("John");
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const handleSubmit = () => {
// startTransition accepts async functions in React 19
startTransition(async () => {
try {
const newName = await updateName(name);
setName(newName);
} catch (e) {
setError(e instanceof Error ? e.message : "Failed to update");
}
});
};
return (
<div>
<input value={name} onChange={e => setName(e.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>
{isPending ? "Updating..." : "Update"}
</button>
{error && <p className="text-red-500">{error}</p>}
</div>
);
}ref as a Prop (No forwardRef)
Classic Hooks EnhancedReact 19 removes the need for forwardRef. You can now pass ref as a regular prop to function components.
View Official Docsimport { useRef, type Ref } from "react";
interface MyInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label: string;
ref?: Ref<HTMLInputElement>; // ref is just a regular prop
}
function MyInput({ label, ref, ...props }: MyInputProps) {
return (
<label>
{label}
<input ref={ref} {...props} />
</label>
);
}
export function Form() {
const inputRef = useRef<HTMLInputElement>(null);
return (
<div>
<MyInput label="Username" ref={inputRef} />
<button onClick={() => inputRef.current?.focus()}>
Focus Input
</button>
</div>
);
}Directives ('use server' & 'use client')
Server ComponentsDirectives to define module boundaries. 'use client' marks client-side interactive boundaries, 'use server' marks server-only modules or Server Actions.
View Official Docs// data.ts
'use server'
import { db } from "./db";
// This function can be called from client components (Server Action)
export async function createPost(formData: FormData) {
const title = formData.get("title") as string;
await db.posts.insert({ title });
}
// ==========================================
// ClientComponent.tsx
'use client'
import { createPost } from "./data";
export function NewPost() {
return (
<form action={createPost}>
<input name="title" />
<button type="submit">Create</button>
</form>
);
}React.cache()
Server ComponentsCache the results of a function call. Mostly used in Server Components to deduplicate data fetching during a single render pass.
View Official Docsimport { cache } from "react";
import { db } from "./db";
// The cached function will only query the DB once per request,
// even if called multiple times across different Server Components.
export const getUser = cache(async (id: string) => {
const user = await db.users.findById(id);
return user;
});
// Component A
async function ProfileHeader({ id }: { id: string }) {
const user = await getUser(id);
return <h1>{user.name}</h1>;
}
// Component B
async function ProfileDetails({ id }: { id: string }) {
// Reuses the promise/result from the first call!
const user = await getUser(id);
return <p>{user.bio}</p>;
}<form action={...}> Pattern
Form HooksReact 19 natively supports passing a function to the action prop of a <form>. It automatically prevents default and handles FormData.
View Official Docsexport default function Search() {
// formData is automatically passed to the action function
function searchAction(formData: FormData) {
const query = formData.get("query") as string;
alert("Searching for: " + query);
}
return (
// No more onSubmit={e => { e.preventDefault(); ... }}
<form action={searchAction}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}Document Metadata Hoisting
Classic Hooks EnhancedRender <title>, <meta>, and <link> tags from any component anywhere in the tree. React 19 will automatically hoist them to the <head>.
View Official Docsfunction BlogPost({ post }: { post: { title: string, excerpt: string } }) {
return (
<article>
{/* React 19 hoists these tags to document <head> */}
<title>{post.title} - My Blog</title>
<meta name="description" content={post.excerpt} />
<link rel="canonical" href="https://myblog.com/posts/..." />
<h1>{post.title}</h1>
<p>{post.excerpt}</p>
</article>
);
}Handpicked Partner Deals & Gear
Discover top-rated mechanical keyboards, 4K monitors, coding software, and curated developer workstation bundles.
Cite & Link This Resource
Backlink MagnetWriting a blog post, GitHub README, or docs? Embed a backlink snippet or badge to cite this cheat sheet.
[React 19 Hooks & Patterns Reference](https://devdossier.com/resources/react-19-hooks-patterns) - Interactive Reference & Cheat Sheet via DevDossier