DEV Community

Nelson chege
Nelson chege

Posted on • Updated on

working with Server Actions

Server actions were introduced in NextJs version 13.4 in Alpha together with turbopack (Beta) and App router(stable).

They have a good developer Experience when using them plus other features that are really nice to have.

with server actions:

  • allows progressive Enhancement which allows forms to function correctly without javascript
  • you can now you forms inside of server action, reducing the amount of javascript shipped to the client
  • you don't need to create other endpoints todo mutations. (but these actions are considered as api endpoints by nextjs)

Because at the moment,server Actions is still in Alpha, you have to add this to your next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    serverActions: true,
  },
};

module.exports = nextConfig;
Enter fullscreen mode Exit fullscreen mode

now creating a simple form that calls an action

import { addTodo } from "../lib/actions";
const AddTodo = () => {
  return (
    <div>
      <form action={addTodo}>
        <div className="">
          <input
            type="text"
            name="todo"
            required
          />
        </div>
        <div>
          <button
            type="submit"
           >
            Submit
          </button>
        </div>
      </form>
    </div>
  );
};

export default AddTodo;
Enter fullscreen mode Exit fullscreen mode

server actions can be imported and saved in a separate file making them cool to work with.

the "use server" must be included on top of the file

"use server";

import { randomUUID } from "crypto";
import { revalidatePath } from "next/cache";

export async function addTodo(data: FormData) {
  const todo = data.get("todo");

  await fetch("http://localhost:3500/todos", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      todo,
      userId: randomUUID,
    }),
  });

  revalidatePath("/");
}
Enter fullscreen mode Exit fullscreen mode

inside the Action you are able to do all the things that a normal API endpoint used to handle such as communicating to a database

the revalidatePath will update the cache with the new data add to the specified path.

And thats all required to get started using server actions.

An extra feature that can be included inside server action is the useTransition hook.
This provides pending and startTransitions to play around with. you can disable the button using the pending status.

"use client";

import React, { useRef, useTransition } from "react";

type AddTodoFormProps = { addTodo: (todo: string) => Promise<void> };

const AddTodoForm = ({ addTodo }: AddTodoFormProps) => {
  const todoRef = useRef<HTMLInputElement>(null);
  let [pending, startTransition] = useTransition();
  return (
    <>
      <div className="">
        <input
          ref={todoRef}
          type="text"
          id="todo"
          name="todo"
          required
        />
      </div>
      <div>
        <button
          disabled={pending}
          onClick={async () => {
            startTransition(async () => {
              await addTodo(todoRef.current!.value);
            });
          }}
        >
          Submit
        </button>
      </div>
    </>
  );
};

export default AddTodoForm;
Enter fullscreen mode Exit fullscreen mode

for the action, data passed to the action will only be that one variable

"use server";

import { randomUUID } from "crypto";
import { revalidatePath } from "next/cache";

export async function addTodo(data: string) {
  const todo = data;
  const payload = {
    todo,
    userId: randomUUID(),
    createdAt: new Date(new Date()).toLocaleString(),
  };

  await fetch("http://localhost:3500/todos", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  revalidatePath("/");
}
Enter fullscreen mode Exit fullscreen mode

conclusion

server actions is an easier way to communicate with your backend without extra endpoints and also reduce the javascript code that is passed to the client side.

Top comments (0)