I am having a TS warning when I pass a server action into my client component. It does not give a compile error, so I could ignore but I'd prefer to get rid of the warning.
TS71007: Props must be serializable for components in the "use client" entry file, "clientStatusFormAction" is invalid.
Here is where my server action is defined:
export default async function EditClientStatus({params}: { params: { id: number } }) {
const clientStatus = await getClientStatusById(params.id);
const editClientStatusAction = async (_prevState: any, formData: FormData): Promise<ApiResponse<ClientStatus>> => {
'use server';
// do stuff
}
return (
<div>
<h1>Edit Client Status</h1>
<ClientStatusForm clientStatus={clientStatus.result} clientStatusFormAction={editClientStatusAction} />
</div>
);
}
Here is my client component:
"use client";
// imports removed for brevity
type ClientStatusFormProps = {
clientStatus: ClientStatus,
clientStatusFormAction: (_prevState: any, formData: FormData) => Promise<ApiResponse<ClientStatus>>
};
export default function ClientStatusForm({clientStatus, clientStatusFormAction}: ClientStatusFormProps) {
const [formState, formAction] = useFormState<Promise<ApiResponse<ClientStatus>>, FormData>(clientStatusFormAction, {success: false, error: {errorType: "", messages: []} });
return (
<form action={formAction}>
<div className="flex flex-wrap mb-6">
<GenericInput name="statusName" type="text" label="Status Name" required={true} isTwoColumn={true} maxLength={124} defaultValue={clientStatus.statusName} />
<GenericInput name="description" type="text" label="Status Description" required={true} isTwoColumn={true} maxLength={255} defaultValue={clientStatus.description} />
</div>
<SubmitButton buttonText="Save" />
</form>
);
}
I found a workaround to avoid the lint warning.
I moved my Server Action function into a separate Typescript file that already had 'use server'
directive like so:
//actions.js
'use server'
export const editClientStatusFormAction = async (_prevState: ApiResponse<ClientStatus>, formData: FormData): Promise<ApiResponse<ClientStatus>> => {
//Server action stuff
}
export type EditClientStatusAction = typeof editClientStatusFormAction;
I exported the type of the function and modified my props type on the client component like so:
type ClientStatusFormProps = {
clientStatus: ClientStatus,
clientStatusFormAction: EditClientStatusAction
};
export default function ClientStatusForm({clientStatus, clientStatusFormAction}: ClientStatusFormProps) {
const [formState, formAction] = useFormState<Promise<ApiResponse<ClientStatus>>, FormData>(clientStatusFormAction, {success: false, error: {errorType: "", messages: []} });
return (
<form action={formAction}>
<div className="flex flex-wrap mb-6">
<GenericInput name="statusName" type="text" label="Status Name" required={true} isTwoColumn={true} maxLength={124} defaultValue={clientStatus.statusName} />
<GenericInput name="description" type="text" label="Status Description" required={true} isTwoColumn={true} maxLength={255} defaultValue={clientStatus.description} />
</div>
<SubmitButton buttonText="Save" />
</form>
);
}