Next.js Discord

Discord Forum

Error handling streamed components on the component level

Answered
Mini Rex posted this in #help-forum
Open in Discord
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.

// 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}</>
}
View full answer

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)
@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
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 itself
Mini 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