how to best handle errors from server components/actions?
Unanswered
Arboreal ant posted this in #help-forum
Arboreal antOP
Hi All,
I'm about to implement toasts and notifications so the user's know when things have completed successfully etc. I have an app router nextjs app which is pretty heavy on server components and actions so I'm wondering how best to trigger the toasts.
I'm using shadcn/ui for most of the components so ideally I'd like to keep using it. It uses sonner for handling the toasts with some really pretty animations etc:
https://sonner.emilkowal.ski/toaster
https://ui.shadcn.com/docs/components/sonner
I've got the <Toaster /> component in my root layout, but I can't call the
In normal react everything would be running on the client and would be easy. With the app router and next though I'm not sure how to do that though.
Ideally I'd like to be able to call some function from a server action and have that trigger the displaying of toasts. If that's not possible then I suppose I'll just have to make sure I have client components which call the server actions so they can trigger the toasts.
Hopefully someone else has solved this problem already and can give me some tips. Thanks!
I'm about to implement toasts and notifications so the user's know when things have completed successfully etc. I have an app router nextjs app which is pretty heavy on server components and actions so I'm wondering how best to trigger the toasts.
I'm using shadcn/ui for most of the components so ideally I'd like to keep using it. It uses sonner for handling the toasts with some really pretty animations etc:
https://sonner.emilkowal.ski/toaster
https://ui.shadcn.com/docs/components/sonner
I've got the <Toaster /> component in my root layout, but I can't call the
toast('test') function from my server components.In normal react everything would be running on the client and would be easy. With the app router and next though I'm not sure how to do that though.
Ideally I'd like to be able to call some function from a server action and have that trigger the displaying of toasts. If that's not possible then I suppose I'll just have to make sure I have client components which call the server actions so they can trigger the toasts.
Hopefully someone else has solved this problem already and can give me some tips. Thanks!
4 Replies
Arboreal antOP
I've reworked my server actions to either return
This means I can easily check if the error is present, and if it is I can do things like trigger a toast in client components.
It does make my server components a bit messier though. Most of my server components call some sort of get function(s), then pass that down as props to child components with some layout code.
Instead of just calling each get function and then passing the data through to props, I need to check for each get request if it has an error or not and early return if it does. This doesn't feel super ergonomic.
I've been reading the docs on the error.tsx files and it looks like it might potentially work to catch any errors thrown by the get requests, but it doesn't allow me much customisation as it only shows the digest.
Ideally if an error is thrown during a get I'd like to not render certain child components and show a toast to the user. Should I maybe set up a "use client" <ErrorMessage /> component which I can pass in the res.error to display 404, 422, etc with some human readable error info and trigger a toast? My only concern with this approach is I then lose the digest info which is handy for debugging.
This can't be a unique situation, but most of the google results are either how to set up an error.tsx page, or how to handle form submission errors. Not super useful.
{data: T, error: null} | {data: null, error: {statusCode: number, message: string}This means I can easily check if the error is present, and if it is I can do things like trigger a toast in client components.
It does make my server components a bit messier though. Most of my server components call some sort of get function(s), then pass that down as props to child components with some layout code.
Instead of just calling each get function and then passing the data through to props, I need to check for each get request if it has an error or not and early return if it does. This doesn't feel super ergonomic.
I've been reading the docs on the error.tsx files and it looks like it might potentially work to catch any errors thrown by the get requests, but it doesn't allow me much customisation as it only shows the digest.
Ideally if an error is thrown during a get I'd like to not render certain child components and show a toast to the user. Should I maybe set up a "use client" <ErrorMessage /> component which I can pass in the res.error to display 404, 422, etc with some human readable error info and trigger a toast? My only concern with this approach is I then lose the digest info which is handy for debugging.
This can't be a unique situation, but most of the google results are either how to set up an error.tsx page, or how to handle form submission errors. Not super useful.
Holland Lop
you can use error boundary to catch all the erors:
// ErrorBoundary.tsx
const ErrorBoundary = ({ children }) => {
try {
return #Unknown Channel{children}</>
} catch(e) {
// show toast notification
}
}
// Component.tsx
import ErrorBoundary from './ErrorBoundary'
const Component = ( ) => {
return <ErrorBoundary>
// your component
</ErrorBoundary>
}
// ErrorBoundary.tsx
const ErrorBoundary = ({ children }) => {
try {
return #Unknown Channel{children}</>
} catch(e) {
// show toast notification
}
}
// Component.tsx
import ErrorBoundary from './ErrorBoundary'
const Component = ( ) => {
return <ErrorBoundary>
// your component
</ErrorBoundary>
}
Arboreal antOP
Yeah the problem with error boundaries is once you do a prod deploy the actual error messages get stripped out and replaced with digests. So it's impossible to give any kind of useful info to the client about what actually went wrong.
For now I've implemented what I posted above.
Whilst searching for a way to scroll after calling
https://github.com/vercel/next.js/discussions/57566#discussioncomment-8506635
Whilst searching for a way to scroll after calling
redirect( from a server action I found this reply which might work for me:https://github.com/vercel/next.js/discussions/57566#discussioncomment-8506635