# Using server functions

Our goal in this tutorial is to use no client-side JavaScript and no React hydration. We only want to use React Server Components and Server Functions. Is this possible? Absolutely!

## Project setup

Let’s create a new project, by creating a new folder, initializing pnpm and installing all the required dependencies.

```bash
mkdir todo
cd todo
pnpm init
pnpm add @lazarv/react-server better-sqlite3 zod
pnpm add -D @types/better-sqlite3 @types/react @types/react-dom autoprefixer postcss tailwindcss@3 typescript
pnpx tailwindcss@3 init -p
```

To store our Todo items, we will use a local Sqlite database. For validation, we will use Zod and for styling we will use Tailwind CSS. To include all our source code as Tailwind content, change the **tailwind.config.js** to this:

```jsx filename="./tailwind.config.js"
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.tsx"],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

As we will not do any exciting Tailwind styling, put the usual 3-liner Tailwind setup into **src/index.css**:

```css filename="./src/index.css"
@tailwind base;
@tailwind components;
@tailwind utilities;
```

## Hello World!

Well it’s nothing better than a good old “Hello World!” app, so let’s create an entrypoint for our Todo app! Put the following code into **src/index.tsx**:

```jsx filename="./src/index.tsx"
export default function Index() {
  return (
	  <h1>Hello World!</h1>
  );
}
```

To run this micro-app, you can just use `pnpm react-server ./src/index.tsx` . To make our life easier, let’s add some npm scripts to **package.json**:

```jsx filename="./package.json"
"scripts": {
  "dev": "react-server ./src/index.tsx",
  "build": "react-server build ./src/index.tsx",
  "start": "react-server start"
},
```

After doing this, use `pnpm dev` to start the development server. After our development server is running, open [http://localhost:3000](http://localhost:3000) and be proud of our Hello World! app. You can also use `pnpm dev --open` to do so.

## Layout

Our Todo app needs a layout, so let’s create **src/Layout.tsx**:

```jsx filename="./src/Layout.tsx"
export default function Layout({ children }: React.PropsWithChildren) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Todo</title>
      </head>
      <body>
        <div className="p-4">
          <h1 className="text-4xl font-bold mb-4">
            <a href="/">Todo</a>
          </h1>
          {children}
        </div>
      </body>
    </html>
  );
}
```

Nothing fancy here, just a usual HTML document template. We will use this Layout component as a wrapper for our app.

## Page

Our main page will be the Todo app, where we will use all of the building blocks to create our app. Let’s say goodbye to Hello World! and change the component to this:

```jsx filename="./src/index.tsx"
import "./index.css";

import { allTodos } from "./actions";
import AddTodo from "./AddTodo";
import Item from "./Item";
import Layout from "./Layout";

export default function Index() {
  const todos = allTodos();

  return (
    <Layout>
      <AddTodo />
      {todos.length === 0 && <p className="text-gray-500">No todos yet!</p>}
      {todos.map((todo) => (
        <Item key={todo.id} title={todo.title} id={todo.id} />
      ))}
    </Layout>
  );
}
```

In this React Server Component, we collect all the stored Todo items by calling `allTodos()` and use the result to render JSX. We use the Layout component to wrap our content into a HTML document.

## Item

To render our items, let’s create an Item component in **src/Item.tsx**:

```jsx filename="./src/Item.tsx"
import { deleteTodo } from "./actions";

type Props = {
  id: number;
  title: string;
};
export default function Item({ id, title }: Props) {
  return (
    <div className="flex row items-center justify-between py-1 px-4 my-1 rounded-lg text-lg border bg-gray-100 text-gray-600 mb-2">
      <p className="flex-1">{title}</p>
      <form action={deleteTodo}>
        <input type="hidden" name="id" value={id} />
        <button className="font-medium">Delete</button>
      </form>
    </div>
  );
}
```

The Item component will render our Todo item using an `id` and `title` prop. But what about that ``? It’s a server function! When the user will submit the form by clicking on the “Delete” button, the browser will call our server function. This is possible without any JavaScript on the frontend, as React supports progressive enhancement for server functions and the initial form action will call the server function by including a hidden input field in the form:

```jsx filename="./src/Item.tsx"
<input type="hidden" name="$ACTION_ID_/Users/lazarv/Projects/tutorials/todo/src/actions.ts#deleteTodo">
```

The runtime will resolve this `$ACTION_ID_` prefixed path to the server function and it will call our server function function!

## Server functions

We will use server functions to implement all functionality of our Todo app. This is the most complex part of the app, but don’t shy away, it’s still really very simple, let’s create **src/actions.ts**:

```jsx filename="./src/actions.ts"
"use server";

import { redirect } from "@lazarv/react-server";
import Database from "better-sqlite3";
import * as zod from "zod";

const db = new Database("db.sqlite");
db.exec(
  "CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT)"
);

type Todo = {
  id: number;
  title: string;
};

const addTodoSchema = zod.object({
  title: zod
    .string()
    .min(3, "Title must be at least 3 characters")
    .max(100, "Title must be at most 100 characters")
    .refine((value) => value.length > 0, "Title is required")
    .transform((value) => value.trim()),
});

const deleteTodoSchema = zod.object({
  id: zod.string().transform((value) => parseInt(value.trim(), 10)),
});

export async function addTodo(formData: FormData) {
  const result = addTodoSchema.safeParse(Object.fromEntries(formData));

  if (!result.success) {
    throw result.error.issues;
  }

  const { title } = result.data;
  db.prepare("INSERT INTO todos(title) VALUES (?)").run(title);
  redirect("/");
}

export function allTodos() {
  return db.prepare("SELECT * FROM todos").all() as Todo[];
}

export async function deleteTodo(formData: FormData) {
  const result = deleteTodoSchema.safeParse(Object.fromEntries(formData));

  if (!result.success) {
    throw result.error.issues;
  }

  const { id } = result.data;
  db.prepare("DELETE FROM todos WHERE id = ?").run(id);
  redirect("/");
}
```

In the first line of this file, we instruct the runtime to treat this file as a server function module using the `"use server";` directive. All exported async functions will be available for us to use as server functions.

We initialize the Sqlite database on module import and create Zod schemas for item add and delete operations.

In all server functions, you will receive a `FormData` instance, including all the fields we define in the forms. We `safeParse` these after converting to JavaScript objects using `Object.fromEntries`.

If Zod validation fails, we throw the validation issues as an error.

On success, we run a database command to INSERT or DELETE the Todo item.

At the end, we are using `redirect` to navigate the user back from the server function call. This is needed as we don’t want the user to use a browser page refresh to create or delete the Todo item again, reusing the form submit.

We also implemented the `allTodos` function here, to have all the storage related code in a single file.

## Add new item

To implement the AddTodo component, create an **src/AddTodo.tsx** file with the following content:

```jsx filename="./src/AddTodo.tsx"
import { useActionState } from "@lazarv/react-server/router";
import type { ZodIssue } from "zod";

import { addTodo } from "./actions";

export default function AddTodo() {
  const { formData, error } = useActionState<
    typeof addTodo,
    string & Error & ZodIssue[]
  >(addTodo);

  return (
    <form action={addTodo} className="mb-4">
      <div className="mb-2">
        <input
          name="title"
          type="text"
          className="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg p-2.5"
          defaultValue={formData?.get?.("title") as string}
          autoFocus
        />
      </div>
      <button
        className="text-white bg-blue-700 hover:bg-blue-800 rounded-lg px-5 py-2 mb-2 text-center"
        type="submit"
      >
        Submit
      </button>
      {error?.map?.(({ message }, i) => (
        <p
          key={i}
          className="bg-red-50 border rounded-lg border-red-500 text-red-500 p-2.5 mb-2"
        >
          {message}
        </p>
      )) ??
        (error && (
          <p className="bg-red-50 border rounded-lg border-red-500 text-red-500 p-2.5">
            {error}
          </p>
        ))}
    </form>
  );
}
```

We already know, how to use server functions from a ``. But what about the result of our server function call? `useActionState` to the rescue!

By passing the `addTodo` server function function reference to `useActionState` , we can get the result of the server function call when this specific server function was called, so we can collect the `error` result. This will be the Zod error issues we thrown in the add server function. So we can iterate on all Zod validation issues here and render validation error messages on the server side.

## Production build

During using the development server, you can notice that the page loaded some JavaScript modules in the browser. This is only used for Hot Module Replacement. In a production build, only the document and a CSS asset will be loaded in the browser.

To build for production, run `pnpm build` and then you can start the production server using `pnpm start` . 

## Final words

That’s it! We have a working small Todo example. You can also find the example on [GitHub](https://github.com/lazarv/react-server/tree/main/examples/todo). By using the above approach, it will be easy for you to add a Todo item update feature, marking an item as completed. We don’t used any client components here, that will be in another tutorial.