Error handling streamed components on the component level
Answered
Mini Rex posted this in #help-forum
Mini RexOP
Hi, I finished with the "Learn Next.js" tour a day ago and now I'm trying to figure out if there is a way to handle errors within a component so that my page can at least load partially and avoid the error getting caught at the route level error boundary (error.js).
So far using a simple try/catch within the component works but I'm not sure if it there is a more idiomatic way of doing so, and maybe I'm just unable to find the "official" way of doing it. Also I'm concerned if there are any risks of doing it this way as well because of some footguns that I'm not aware of.
Here is a simple example of how I did it.
tl;dr - Is there a better way of handling the error on the component level, and are there any potential footguns doing it this way or alternatively.
🙠Ty
So far using a simple try/catch within the component works but I'm not sure if it there is a more idiomatic way of doing so, and maybe I'm just unable to find the "official" way of doing it. Also I'm concerned if there are any risks of doing it this way as well because of some footguns that I'm not aware of.
Here is a simple example of how I did it.
// actions.ts
'use server';
export async function hello(): Promise<string> {
return 'hello';
}
export async function oops(): Promise<string> {
await new Promise((res) => setTimeout(res, 2000));
throw new Error('poof');
return 'oops';
}// hello.tsx
export default async function Hello() {
const something = await hello();
return <div>{something}</div>;
}// oops.tsx
export default async function Oops() {
try {
const something = await oops();
return <div>{something}</div>;
} catch (error) {
return <div>{error.message}</div>;
}
}// page.tsx
export default function Page() {
return (
<div>
<Suspense fallback={'Loading hello...'}>
<Hello />
</Suspense>
<Suspense fallback={'Loading oops...'}>
<Oops />
</Suspense>
</div>
);
}tl;dr - Is there a better way of handling the error on the component level, and are there any potential footguns doing it this way or alternatively.
🙠Ty
Answered by Siricid woodwasp
From what I've seen, other Next apps do something similar to you, except they usually use an if/else to show the error case, since the object from the fetch is often a JSON object with something like { data, errors }. I don't think there's anything wrong with a try catch, but I have the error handling logic in a function separate from my components so I can reuse it for different requests.
export default async function Oops() {
const something = await oops();
if (something.error) return <></>
return <>{something.data}</>
}8 Replies
Siricid woodwasp
From what I've seen, other Next apps do something similar to you, except they usually use an if/else to show the error case, since the object from the fetch is often a JSON object with something like { data, errors }. I don't think there's anything wrong with a try catch, but I have the error handling logic in a function separate from my components so I can reuse it for different requests.
export default async function Oops() {
const something = await oops();
if (something.error) return <></>
return <>{something.data}</>
}Answer
@Mini Rex Hi, I finished with the "Learn Next.js" tour a day ago and now I'm trying to figure out if there is a way to handle errors within a component so that my page can at least load partially and avoid the error getting caught at the route level error boundary (error.js).
So far using a simple try/catch within the component works but I'm not sure if it there is a more idiomatic way of doing so, and maybe I'm just unable to find the "official" way of doing it. Also I'm concerned if there are any risks of doing it this way as well because of some footguns that I'm not aware of.
Here is a simple example of how I did it.
javascript
// actions.ts
'use server';
export async function hello(): Promise<string> {
return 'hello';
}
export async function oops(): Promise<string> {
await new Promise((res) => setTimeout(res, 2000));
throw new Error('poof');
return 'oops';
}
javascript
// hello.tsx
export default async function Hello() {
const something = await hello();
return <div>{something}</div>;
}
javascript
// oops.tsx
export default async function Oops() {
try {
const something = await oops();
return <div>{something}</div>;
} catch (error) {
return <div>{error.message}</div>;
}
}
javascript
// page.tsx
export default function Page() {
return (
<div>
<Suspense fallback={'Loading hello...'}>
<Hello />
</Suspense>
<Suspense fallback={'Loading oops...'}>
<Oops />
</Suspense>
</div>
);
}
tl;dr - Is there a better way of handling the error on the component level, and are there any potential footguns doing it this way or alternatively.
🙠Ty
you can handle errors with [
react-error-boundary](https://github.com/bvaughn/react-error-boundary) or any client-side [react error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)@joulev you can handle errors with [`react-error-boundary`](<https://github.com/bvaughn/react-error-boundary>) or any client-side [react error boundaries](<https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary>)
is not the error.tsx already wrap code in react error boundary ? Or this wrapper does not work for isolated components ? Never tried so tbh
@walid-mos is not the error.tsx already wrap code in react error boundary ? Or this wrapper does not work for isolated components ? Never tried so tbh
yes, error.tsx is an implicit error boundary like how loading.tsx is an implicit Suspense boundary
so if you throw rendering errors (server or client errors) in your page.tsx file, the nearest same-level or higher-level error.tsx files will capture that error
Yes but for example imagine i have a page tsx importing a renderData.tsx (RSC), the error boundary would wrap all the page, even if the error is thrown in renderData ?
@walid-mos Yes but for example imagine i have a page tsx importing a renderData.tsx (RSC), the error boundary would wrap all the page, even if the error is thrown in renderData ?
it's like this
if your
if you need to catch the error before it becomes a render error you need to put a
async function Page() {
await renderData();
return stuff;
}if your
renderData doesn't return but instead throws with an error, the error simply propagates. in this case since there's nothing that catch it, that error will terminate rendering of the Page component and that is a rendering error captured by error boundaries.if you need to catch the error before it becomes a render error you need to put a
try catch around your renderData call or inside the renderData function itselfMini RexOP
Thank you all for the replies â¤ï¸
I will mark the try/catch answer as it does seem like something I would want to explore more, especially now that it's not that wrong of an approach.
(I will probably have centralized error handling in some component that will either render the actual component if all goes right, or render an error message type of component depending on the error handling)
Also react-error-boundary seems cool and I will deffo give it a try at some point in the future too!
Cheers
I will mark the try/catch answer as it does seem like something I would want to explore more, especially now that it's not that wrong of an approach.
(I will probably have centralized error handling in some component that will either render the actual component if all goes right, or render an error message type of component depending on the error handling)
Also react-error-boundary seems cool and I will deffo give it a try at some point in the future too!
Cheers