Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Delete button requires me to turn server component to client component

I have an app in Next.js v13.4. In the app, I have a server component where I get all users from the database and display them in separate cards. I want each card to have a delete button but when I add an event listener on the button, it gives me an error:

Unhandled Runtime Error Error: Event handlers cannot be passed to Client Component props.
  <button onClick={function} children=...>
                  ^^^^^^^^^^
If you need interactivity, consider converting part of this to a Client Component.

Here’s the code of my component:

// import { useRouter } from "next/navigation";
import Link from "next/link";
import dbConnect from "../lib/dbConnect";
import User from "../models/User";

export default async function Home() {
    // const router = useRouter();
    const data = await getData();
    const users = data.props.users;

    const handleDelete = async (id: any) => {
        try {
            await fetch(`/api/users/${id}`, {
                method: "Delete",
            });
            // router.push("/");
        } catch (error) {
            console.log("error ===> ", error);
        }
    };

    return (
        <main className="main">
            <h1>Home page</h1>
            {users ? (
                <div className="users">
                    {users.map((user) => (
                        <div key={user._id}>
                            <div className="card">
                                <h3 className="user-name">Name: {user.name}</h3>
                                <p className="email">Email: {user.email}</p>
                                <p className="email">
                                    Password: {user.password}
                                </p>
                                <p className="email">Country: {user.country}</p>
                                <button onClick={(_id) => handleDelete(_id)}>Delete</button>
                            </div>
                        </div>
                    ))}
                    <Link className="add-btn-link" href="/new">
                        <div className="add-btn">
                            <p>+</p>
                        </div>
                    </Link>
                </div>
            ) : (
                <p>No users</p>
            )}
        </main>
    );
}

async function getData() {
    await dbConnect();

    /* find all the data in our database */
    const result = await User.find({});
    const users = result.map((doc) => {
        const user = doc.toObject();
        user._id = user._id.toString();

        return user;
    });

    return { props: { users: users } };
}

Here’s the screenshot of the photo:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error screenshot

It’s also telling me that I can’t use useRouter(). Here’s the error message:

Error: useRouter only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component

I think I need to separate some parts to a separate component but I’m not sure how.

>Solution :

For a server component, the idea is to not send any JavaScript coming from it. For the code of your click handler to make it to the browser, you need a client component. You could create a CardDeleteButton.tsx in which you add:

"use client";

import { useRouter } from "next/navigation";

export default function CardDeleteButton.tsx({ id }: { id: string }) {
  const router = useRouter();
  const handleDelete = async (id: string) => {
    try {
      await fetch(`/api/users/${id}`, {
        method: "Delete",
      });
      router.push("/");
    } catch (error) {
      console.log("error ===> ", error);
    }
  };

  return <button onClick={() => handleDelete(id)}>Delete</button>;
}

Import it in your Home component and call it in place of your current button:

<CardButton id={user._id} />

This way you can keep the page as a server component.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading