Callback after server action is successful
Answered
Spectacled bear posted this in #help-forum
Spectacled bearOP
Hi everyone, I'm using NextJS 14 and looking for a way to add a callback after I have submitting a form using server action. The idea is to present some sort of alert or clear input field after the server action is successful.
This is what I come up with but to be honest it is ugly as hell. Any help is appreciated!
This is my client component
This is my action
This is what I come up with but to be honest it is ugly as hell. Any help is appreciated!
This is my client component
export const Example = () => {
const [state, formAction] = useFormState(uploadFile, null);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (!state) {
return;
}
setErrorMessage(state.isError ? state.message : null);
if (!state.isError && fileInputRef.current) {
fileInputRef.current.value = "";
}
}, [state]);
return (
<div>
{errorMessage && <p>{errorMessage}</p>}
<form action={formAction}>
<input name="file" ref={fileInputRef} type="file"/>
</form>
</div>
);
}; This is my action
export const uploadFile = async (
prevState: {
isError: boolean;
message: string;
} | null,
formData: FormData
) => {
"use server";
const files = formData.get("file") as File;
try {
// upload file here
return { isError: false, message: "Success" };
} catch (e) {
return { isError: true, message: "Failed to Upload" };
}
};Answered by Ray
export const Example = () => {
const [state, setState] = useState({});
const formRef = useRef<HTMLFormElement>(null)
return (
<div>
{state?.message && <p>{state?.message}</p>}
<form ref={formRef} action={async (data) => {
const result = await uploadFile(data)
setState(result)
formRef.current?.reset()
}} className="w-full">
<input type="file"/>
</form>
</div>
);
};5 Replies
export const Example = () => {
const [state, formAction] = useFormState(uploadFile, null);
const formRef = useRef<HTMLFormElement>(null)
return (
<div>
{state.message && <p>{state.message}</p>}
<form ref={formRef} action={async () => {
await formAction()
formRef.current?.reset()
}} className="w-full">
<input type="file"/>
</form>
</div>
);
};Spectacled bearOP
Thanks for the quick response Ray! but it seems that formAction is not a function that return promise, so await here does nothing :(. Furthermore, this approach only handles when the formAction completes, I wonder if we can trigger the clean up only when formAction succeeds?
ah use useState instead then
export const Example = () => {
const [state, setState] = useState({});
const formRef = useRef<HTMLFormElement>(null)
return (
<div>
{state?.message && <p>{state?.message}</p>}
<form ref={formRef} action={async (data) => {
const result = await uploadFile(data)
setState(result)
formRef.current?.reset()
}} className="w-full">
<input type="file"/>
</form>
</div>
);
};Answer
Spectacled bearOP
You're awesome! Never thought we could directly call a server action like that. Much appreciated!