Server client component composition
Unanswered
Russian Blue posted this in #help-forum
Russian BlueOP
I have a server component (Card), inside it I have a button that I want to delete the object, what is the best practice on implementing this?
42 Replies
Russian BlueOP
server component
import { Task } from "@prisma/client";
import { GiTrashCan } from "react-icons/gi";
import IconWrapper from "./IconWrapper";
const TaskCard = ({ task }: { task: Task }) => {
const IconOnClick = () => {
console.log("Clicked Icon");
};
return (
<div className="bg-gray-100 rounded-md p-3 w-[200px] h-[100px] flex flex-row">
<div>
<h1 className="text-xl">{task.title}</h1>
<h6>{task.description}</h6>
<p className="text-gray-500">{task.createdAt.toDateString()}</p>
</div>
<IconWrapper>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</IconWrapper>
</div>
);
};
export default TaskCard;"use client";
const IconWrapper = ({ children }: { children: React.ReactNode }) => {
return <div>{children}</div>;
};
export default IconWrapper;I feel this is redundant work, since I cannot pass an onclick prop inside the server component to the wrapper
what would you want to do after delete?
Russian BlueOP
and if i can get rid of the wrapper even better, or at least make the wrapper so I could reuse it with other objects/server actions
you could use form
@Ray what would you want to do after delete?
Russian BlueOP
remove the object from the list
yea i mean any other stuff you want to do?
Russian BlueOP
nope idts
use form for it
Russian BlueOP
okay lets say if i wanted to have an alert modal to ask again to make sure? how can I handle that?
<form action={action.bind(null, id)}>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</form>American
You can use a hidden input for the id if you use a form
Or bind the server action to an id
@Russian Blue okay lets say if i wanted to have an alert modal to ask again to make sure? how can I handle that?
'use client'
<form action={async () => {
await action(id)
alert("deleted")
}}>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</form>American
Personally I try to use useFormState for client feedback
@American Personally I try to use useFormState for client feedback
Russian BlueOP
I would have to make it a client component then right?
with
useFormState, the action cannot be awaitAmerican
Ray the goat, always being so helpful
will need to use
useEffect@Russian Blue I would have to make it a client component then right?
American
Yes ðŸ‘
Russian BlueOP
or do I just make the delete button a client component and do all the logic there?
because form work even without javascript
but it doesn't matter if you page won't show without javascript
Russian BlueOP
yes I meant put the form in another client compnent to make it interactive, would this work fine as well?
use client component if you need interactive
Russian BlueOP
but is there a way to pass a server action as prop from server component ot client component? to make the component reusable to delete other objects
you can use form only if you just redirect to other page
@Russian Blue but is there a way to pass a server action as prop from server component ot client component? to make the component reusable to delete other objects
<ClientComponent action={serverAction} />Russian BlueOP
alright awesome! Thank you so much!!
@Ray `<ClientComponent action={serverAction} />`
Russian BlueOP
just to make sure, what do i set the type of the action to for typescript
@Russian Blue just to make sure, what do i set the type of the action to for typescript
I usually do
type Props = {
action: typeof serverAction
}or you have to type it like
type Props = {
action: (id: string) => Promise<{error?: string}>
}Russian BlueOP
deal alright! thanks!
Russian BlueOP
Is it okay to pass to the action attribute a function that includes some client side stuff in adition to the server action:
"use client";
import { GiTrashCan } from "react-icons/gi";
import { deleteTask } from "../action";
import { useState, useTransition } from "react";
const TaskDeleteIcon = ({ taskId }: { taskId: number }) => {
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | undefined>();
const [success, setSuccess] = useState<string | undefined>();
const onSubmit = () => {
setError("");
setSuccess("");
startTransition(() => {
deleteTask(taskId).then((data) => {
setError(data?.error);
setSuccess(data?.success);
});
});
};
return (
<form action={onSubmit}>
<button type="submit" disabled={isPending}>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</button>
</form>
);
};
export default TaskDeleteIcon;@Russian Blue Is it okay to pass to the action attribute a function that includes some client side stuff in adition to the server action: "use client";
import { GiTrashCan } from "react-icons/gi";
import { deleteTask } from "../action";
import { useState, useTransition } from "react";
const TaskDeleteIcon = ({ taskId }: { taskId: number }) => {
const [isPending, startTransition] = useTransition();
const [error, setError] = useState<string | undefined>();
const [success, setSuccess] = useState<string | undefined>();
const onSubmit = () => {
setError("");
setSuccess("");
startTransition(() => {
deleteTask(taskId).then((data) => {
setError(data?.error);
setSuccess(data?.success);
});
});
};
return (
<form action={onSubmit}>
<button type="submit" disabled={isPending}>
<GiTrashCan className="w-6 h-6 cursor-pointer hover:bg-red-500 p-[2px] rounded" />
</button>
</form>
);
};
export default TaskDeleteIcon;
I think startTransition would not work without javascript so in this case you can pass it either action or onSubmit props
Russian BlueOP
if is pass the onSubnmit as OnSubmit prop the page will reload, should i add e.preventDefault()?
Russian BlueOP
alright, bless you!