#1 Data Analytics Program in India
₹2,499₹1,499Enroll Now
11 min read
•Question 32 of 47hard

Advanced Server Actions Patterns

Complex patterns for Server Actions.

Advanced Server Actions

Optimistic Updates

code.txtTSX
'use client';

import { useOptimistic } from 'react';
import { addTodo } from './actions';

export function TodoList({ todos }: { todos: Todo[] }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo: Todo) => [...state, newTodo]
  );

  async function handleSubmit(formData: FormData) {
    const newTodo = {
      id: Date.now(),
      text: formData.get('text'),
      pending: true,
    };

    addOptimisticTodo(newTodo);
    await addTodo(formData);
  }

  return (
    <form action={handleSubmit}>
      <input name="text" />
      <button type="submit">Add</button>
      <ul>
        {optimisticTodos.map((todo) => (
          <li key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
            {todo.text}
          </li>
        ))}
      </ul>
    </form>
  );
}

Error Handling with useFormState

code.txtTSX
'use client';

import { useFormState, useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? 'Saving...' : 'Save'}</button>;
}

export function Form() {
  const [state, action] = useFormState(updateUser, { error: null });

  return (
    <form action={action}>
      <input name="email" />
      {state.error && <p className="error">{state.error}</p>}
      <SubmitButton />
    </form>
  );
}

Progressive Enhancement

code.txtTSX
// Works without JavaScript
'use server';

export async function subscribe(formData: FormData) {
  const email = formData.get('email');
  await db.subscribers.create({ email });
  redirect('/thank-you');
}

// Form works with or without JS
<form action={subscribe}>
  <input name="email" type="email" required />
  <button>Subscribe</button>
</form>