Simplifying Next.js Server Actions

Share with a friend:

Next.js Server Actions unlock powerful data-fetching capabilities in Next.js applications. This feature leverages React Server Components to optimize performance and minimize bundle size.

Understanding React Server Components

React Server Components (RSC) represents a paradigm shift in web development. By relocating components to the server and aligning them with data stores, we bypass network roundtrips, resulting in vastly improved app performance without bloating the bundle size.

In Next.js 13, if using the /app directory, components are server components by default. To designate a component as a client component, use the use client directive.

This flexibility allows for a blend of server and client components, maximizing performance and user interactivity.

Demystifying Server Actions

Server Actions in Next.js introduce powerful data fetching techniques. At the time of writing, they are an experimental alpha feature and must be explicitly enabled in next.config.js:

module.exports = { 
  experimental: { 
    serverActions: true, 
  }, 
}

Server Actions are asynchronous JavaScript functions that execute on the server in response to user interactions on the client.

For example:

async function addTodoItem(data) {
  'use server';
  await addTodoItem(data);
}

These actions can be triggered using the action prop of a <form> element in React:

<form action={addTodoItem}>
  {/* Form fields */}
</form>

Alternatively, you can use the formAction prop on elements like submit buttons or input fields within a <form>:

<form>
  <input type="text" id="todo" name="todo" />
  <button type="submit" formAction={addTodoItem}>Add Todo</button>
</form>

Server Actions are defined in server components. However, you may call them from client components by importing them from a separate file.

Implementing Server Actions

Within Server Components

To integrate server actions within a server component, create an async function with the use server directive at the top. This function can then be called from the action prop of a <form> element or via the formAction prop on elements within a <form>.

export default function TodoList() {
  async function addTodoItem(todoId, description) {
    'use server';
    await saveTodo({ todoId, description });
  }

  return (
    <form action={addTodoItem}>
       <input type="text" id="todo" name="todo" />
       <button type="submit">Add Todo</button>
     </form>
  );
}

Using Server Actions in Client Components

In scenarios where both server and client components coexist, you may want to employ server actions within client components. To achieve this, create your actions in a separate file (e.g., add-todos.js) and ensure the use server directive is at the top.

'use server'

export async function addTodoItem(data) {
  await addTodoItem(data);
}

// more server actions here (if needed)...

In the client component, import the actions and invoke them using the action or formAction prop.

'use client'

import { addTodo } from '@/actions/add-todos';

export default function TodoList() {
  return (
    <form action={addTodo}>
      <button type="submit">Add Todo</button>
    </form>
  );
}

Invoking Server Actions Outside of Forms

If you need to trigger a server action outside of a form, leverage the startTransition method provided by the useTransition hook. Assuming your server action resides in a separate file, you can invoke it from a client component without a <form> element.

'use client'

import { useTransition } from 'react'
import { addTodo } from '@/actions/add-todos';

export default function CourseComment() {
  let [isPending, startTransition] = useTransition()

  return (
    <button onClick={() => startTransition((todoId, description) => { 
      addTodoItem(todoId, description);
    })}>
      Add Comment
    </button>
  );
}

Revalidating Data with Server Actions

Server Actions in Next.js integrate seamlessly with the caching and revalidation architecture. When a form is submitted, the Server Action has the capability to update cached data and revalidate any cache keys that should be updated. This is a powerful feature as it allows for multiple actions per route, instead of being limited to a single form per route as in traditional applications. Additionally, the browser doesn’t need to refresh on form submission, as Next.js can efficiently return both the updated UI and refreshed data in a single network roundtrip. This optimizes the performance and responsiveness of the application.

For example:

// app/actions.ts
'use server'
import { revalidatePath } from 'next/cache';

export default async function submit() {
  await updateUserInfo();
  revalidatePath('/profile'); // Revalidate user profile data
}

In this code snippet, the submit() Server Action calls updateUserInfo() to update the user’s information. Afterward, it uses revalidatePath to trigger the revalidation of the user’s profile data.

Redirecting with Server Actions

By using the redirect function from the next/navigation module, you can specify either an absolute or relative URL to redirect users to a different route after a Server Action is completed. For instance, after performing a Server Action like creating an order, you can use redirect to smoothly guide the user to the newly created order page. This feature enhances the user experience by ensuring they are directed to relevant content effortlessly.

// app/actions.ts
'use server'
import { redirect } from 'next/navigation';
import { revalidateTag } from 'next/cache';

export default async function submit() {
  const orderId = await createOrder(); // Assume createOrder() is a Server Action
  revalidateTag('orders'); // Update cached orders
  redirect(`/order/${orderId}`); // Navigate to new route
}

Conclusion

This guide has demonstrated how to effectively utilize Next.js Server Actions and invoke them from client components. While you can start using them now, remember they are still in the experimental phase, so exercise caution as the API may undergo changes in the future.

Share with a friend:

Rajae Robinson

Rajae Robinson is a young Software Developer with over 3 years of work experience building websites and mobile apps. He has extensive experience with React.js and Next.js.

Recent Posts