Need to trigger a client event after a server action.
Answered
LeonN posted this in #help-forum
LeonNOP
I have a form with one field called name. After some validation in a server action, it makes a post request on my API, which will respond with a success or error. If the creation is successful, I want to redirect the user to the root page "/", where my form is. Besides, I want to show a toast message informing the user about the successful result. My toast component is a client component with a global context. How can I trigger the activation of that client component in a server action? I though about returning a success: true on the form action, and in the form, trigger the toast via useEffect tracking the value of the success key of the returned object, but since I want to use the redirect feature on the server action, this won't be possible.
Answered by chisto
you can return a success: true on the form action and redirect in the client component with router.push
if(state.sucess){
toast();
router.push("somewhere")
}
16 Replies
Australian Freshwater Crocodile
Where do you call this action? Directly in the action prop of the form?
Australian Freshwater Crocodile
a) You could instead use the onSubmit on the form, especially if you need data from the event object it gets passed.
The way we used to do it before actions, then inside the handleSubmit()
1- you start an async transition
2- you call and await the action inside the transition,
3- and after getting the response back from the action, you call the toast()
b) just make an async wrapper for the function you pass to the action prop:
The way we used to do it before actions, then inside the handleSubmit()
1- you start an async transition
2- you call and await the action inside the transition,
3- and after getting the response back from the action, you call the toast()
b) just make an async wrapper for the function you pass to the action prop:
<form action = { async (formData) => {
// i assume this "action "is returned from the useActionState hook, right?
const response = await action(formData);
// call your toast
toast()
} } >
you can return a success: true on the form action and redirect in the client component with router.push
if(state.sucess){
toast();
router.push("somewhere")
}
Answer
@chisto you can return a success: true on the form action and redirect in the client component with router.push
if(state.sucess){
toast();
router.push("somewhere")
}
Australian Freshwater Crocodile
Where would you put this logic in?
a) in the render function of the component who's getting the response back
b) inside a use effect that's listening on the "state" variable returned by the action
c) event handler / action callback
I believe this should be considered a side effect and should be done in either an event handler or an action callback wrapper, this logic is being trigger by some user action, it's not part of the component render or sync logic (IMO this shouldn't synchronize inside an useEffect).
a) in the render function of the component who's getting the response back
b) inside a use effect that's listening on the "state" variable returned by the action
c) event handler / action callback
I believe this should be considered a side effect and should be done in either an event handler or an action callback wrapper, this logic is being trigger by some user action, it's not part of the component render or sync logic (IMO this shouldn't synchronize inside an useEffect).
LeonNOP
I ended up follwing the approach mentioned by @chisto . As my form is already a client component, in my form action I removed the redirect and return a result of type success (custom enum). Via use effect I'm tracking changes in the message, so the snackbar can show it, and I'm adding a conditional to verify if the succes type was true, in that case, I will use client side navigation. My doubt is, if using client side navigation has a difference with the redirect api from server navigation. Is it a performance cost or anything?
@LeonN I ended up follwing the approach mentioned by <@138831444461092866> . As my form is already a client component, in my form action I removed the redirect and return a result of type success (custom enum). Via use effect I'm tracking changes in the message, so the snackbar can show it, and I'm adding a conditional to verify if the succes type was true, in that case, I will use client side navigation. My doubt is, if using client side navigation has a difference with the redirect api from server navigation. Is it a performance cost or anything?
Australian Freshwater Crocodile
It works, but if in any case your actions returns the same exact message it won't trigger the effect since the "state.message" effectively did not change.
If you choose to display the toast for error case, and twice you provoke the same error, the action will return the same message
LeonNOP
I'm aware of that. So far, I haven't encountered that issue, since validation errors are displayed in another key of the return object.
Australian Freshwater Crocodile
The useEffect won't synchronize, dependencies didn't change since last time it ran... there's a bug there might bite you later
@LeonN I'm aware of that. So far, I haven't encountered that issue, since validation errors are displayed in another key of the return object.
Australian Freshwater Crocodile
I see, still have that in mind for other use cases
Try to avoid useEffect as much as possible when you have other solutions that make sense, there's even a full article in React docs, soooo long that I would recommend reading, it's called "You Might Not Need an Effect"
Btw I speak spanish too in case you want to talk in private, i'm from Mexico :p
@LeonN I ended up follwing the approach mentioned by <@138831444461092866> . As my form is already a client component, in my form action I removed the redirect and return a result of type success (custom enum). Via use effect I'm tracking changes in the message, so the snackbar can show it, and I'm adding a conditional to verify if the succes type was true, in that case, I will use client side navigation. My doubt is, if using client side navigation has a difference with the redirect api from server navigation. Is it a performance cost or anything?
there's no performance cost or anything, they work the same under the hood
Australian Freshwater Crocodile
"Is it a performance cost or anything?"
I don't think there's a cost, although there's a difference in the way they work:
- router.push("/route") works by pushing a new entry in the history stack of the broswer and preventing the router hard refresh, so it can keep the scroll position
- redirect("/route") works by throwing an error 3XX (redirection error), and Next.js is smart enough to catch this error and push a new entry in the browser history, sending you to that URL.
I don't think there's a cost, although there's a difference in the way they work:
- router.push("/route") works by pushing a new entry in the history stack of the broswer and preventing the router hard refresh, so it can keep the scroll position
- redirect("/route") works by throwing an error 3XX (redirection error), and Next.js is smart enough to catch this error and push a new entry in the browser history, sending you to that URL.
Also, idk if they fixed this already but before if you redirected inside a try{}catch{} it woudn't do anything since the catch block would catch the error lol
LeonNOP
Thank you for the replies. It is good to know there is no problem with client side routing.