React Examples
A handful of React patterns you reach for over and over - data fetching, forms with Zod, optimistic UI, infinite scroll, debounced search.
React by example
EXAMPLE
// 1. Data fetching with TanStack Query
import { useQuery } from '@tanstack/react-query';
function User({ id }: { id: string }) {
const { data, isPending, error } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(\`/api/users/${id}\`).then((r) => r.json()),
staleTime: 60_000,
});
if (isPending) return <p>loading</p>;
if (error) return <p>error: {String(error)}</p>;
return <p>{data.name}</p>;
}
// 2. Form with Zod + react-hook-form
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const Schema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
type Input = z.infer<typeof Schema>;
function Login() {
const { register, handleSubmit, formState: { errors, isSubmitting } } =
useForm<Input>({ resolver: zodResolver(Schema) });
const onSubmit = async (data: Input) => { /* call api */ };
return (
<form onSubmit={handleSubmit(onSubmit)} className='space-y-2'>
<input {...register('email')} type='email' />
{errors.email && <p>{errors.email.message}</p>}
<input {...register('password')} type='password' />
{errors.password && <p>{errors.password.message}</p>}
<button disabled={isSubmitting}>Sign in</button>
</form>
);
}
// 3. Optimistic UI with useOptimistic (React 19)
import { useOptimistic, useTransition } from 'react';
function TodoList({ initial, onAdd }: { initial: Todo[]; onAdd: (text: string) => Promise<void> }) {
const [pending, start] = useTransition();
const [items, addOptimistic] = useOptimistic(initial, (state, text: string) => [
...state,
{ id: 'tmp', text, pending: true },
]);
return (
<>
<form action={(fd) => {
const text = String(fd.get('text'));
start(async () => {
addOptimistic(text);
await onAdd(text);
});
}}>
<input name='text' />
</form>
<ul>{items.map((t) => <li key={t.id} style={{ opacity: t.pending ? 0.5 : 1 }}>{t.text}</li>)}</ul>
</>
);
}
// 4. Infinite scroll with TanStack Query
import { useInfiniteQuery } from '@tanstack/react-query';
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = null }) =>
fetch(\`/api/posts?cursor=${pageParam || ''}\`).then((r) => r.json()),
getNextPageParam: (last) => last.nextCursor ?? undefined,
initialPageParam: null,
});
// 5. Debounced search
import { useState, useEffect } from 'react';
function useDebounce<T>(value: T, ms = 300) {
const [v, setV] = useState(value);
useEffect(() => {
const id = setTimeout(() => setV(value), ms);
return () => clearTimeout(id);
}, [value, ms]);
return v;
}
const [q, setQ] = useState('');
const dq = useDebounce(q, 250);
useEffect(() => {
if (dq.length < 2) return;
fetch(\`/api/search?q=${encodeURIComponent(dq)}\`).then(/* ... */);
}, [dq]);
Why it matters
These five patterns cover most of what an app actually does - fetch data, accept input, react optimistically, paginate, search. Pick a query lib, a form lib, and a UI primitive lib and stop reinventing.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Common snippets — see lesson body. const App = () => <h1>iwantcoding.com React Examples</h1>;Try it Yourself »
Discussion
Loading…