Creating Data with Xata

So currently, our to-do app can Read data from Xata, Update to-do items, and even Delete them. But now, our to-do list is empty! Let's add support for Creating new to-do items, completing the CRUD (Create, Read, Update, and Delete) acronym.

If you're joining us in the middle, we covered deleting data with Xata in the previous section. Maybe read that first before coming here for more context.

Add a New To-do Form

Let's create a form component to add a new to-do item to our list. We'll do this in ./components/AddTodoForm.tsx.

// ./components/AddTodoForm.tsx

import { useState } from "react";

export const AddTodoForm = () => {
  const [name, setName] = useState("");

  const submit = () => {
    fetch("/api/add-todo", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name,
      }),
    }).then(() => window.location.reload());
  };

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        submit();
      }}
    >
      <label style={{ display: "grid", maxWidth: 200 }}>
        New Todo
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Eat breakfast?"
        />
      </label>
      <button>Save</button>
    </form>
  );
};

Let's talk about this. We have a React component that has a single text input and a button. When the user submits the form, we want to prevent the default behavior of navigating away or reloading the page, and instead, call a Next.js API route that creates a new to-do item.

We can add this new component to our list page:

// ./pages/index.tsx

import { FC } from "react";
import { xata } from "../util/xataClient";
+import { AddTodoForm } from "../components/AddTodoForm";

type Props = Awaited<ReturnType<typeof getServerSideProps>>["props"];

const Index: FC<Props> = ({ todos }) => {
  return (
    <main>
      <h1>My To-do List</h1>
+      <AddTodoForm />
      <ul>
        <li>
          {todos.map((t) => (
            <>
              <label key={t.id}>
                <input
                  onClick={() => {
                    fetch("/api/toggle-todo", {
                      method: "POST",
                      headers: {
                        "Content-Type": "application/json",
                      },
                      body: JSON.stringify({ id: t.id, is_done: !t.is_done }),
                    }).then(() => {
                      window.location.reload();
                    });
                  }}
                  type="checkbox"
                  checked={t.is_done}
                />
                {t.label}
              </label>
              <button
                onClick={() => {
                  fetch("/api/delete-todo", {
                    method: "POST",
                    headers: {
                      "Content-Type": "application/json",
                    },
                    body: JSON.stringify({ id: t.id }),
                  }).then(() => {
                    window.location.reload();
                  });
                }}
              >
                Delete
              </button>
            </>
          ))}
        </li>
      </ul>
    </main>
  );
};

export const getServerSideProps = async () => {
  const todos = await xata.db.items.getMany();
  return { props: { todos } };
};

export default Index;

If we reload the page, we'll see the new form to add a to-do item. When we try to submit it, we send a fetch request to something that returns 404 page not found. Yikes! Let's implement the API route to finish this.

Add the API Route

We can copy/paste our existing update API route that we created previously and change it a bit. Here's a diff between the copy/pasted update API route, and the newly created one:

// ./pages/api/add-todo.ts

import { NextApiHandler } from "next";
import { xata } from "../../util/xataClient";

const handler: NextApiHandler = async (req, res) => {
-  const { id, is_done } = req.body;
+  const { label, is_done } = req.body;

-  await xata.db.items.update({ is_done, id });
+  await xata.db.items.create({ is_done, label });
  res.end();
};

export default handler;

We basically just replace id with label, and .update() with .create(), and we're good to go. When we run it, we now can add new to-do list items to our list. We've done it!

Conclusion

We finally have a fully CRUD application built on Xata, set up with the SDK, CLI, and more. To continue your learning journey, let's explore how we add basic authentication to this app and go a bit further. If you'd like to stop here and play, we'd encourage that too!


Last modified 1 mo16 days ago