Double render for falied component with ErrorBoundary in nextjs

Viewed 28

used

"next": "12.2.2",
"react-dom": "^18.2.0",
"@tanstack/react-query": "^4.0.10",

I made Errorboundary component following Docs. And try to expand with suspense.

ErrorBoundary Component :

import React from "react"

const changedArray = (prev = [], now = []) => prev.length !== now.length || prev.some((item, index) => !Object.is(item, now[index]));

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { error: null }
  }
  static getDerivedStateFromError(error) {
    return { error }
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.error === null) {
      return;
    }

    if (changedArray(prevProps.resetKeys, this.props.resetKeys)) {
      this.resetErrorBoundary()
    }
  }

  componentDidCatch(error, errorInfo) {
    //TODO : sentry init
    console.log({ error, errorInfo })
  }

  resetErrorBoundary = () => {
    this.setState({error : null});
  };

  render() {
    const { children, renderFallback } = this.props;
    const {error} = this.state;
    
    if (error !== null) {
      if (React.isValidElement(renderFallback)) {
        return renderFallback;
      }
      
      return renderFallback({
        error,
        reset: this.resetErrorBoundary
      })
    }
    
    return children;
  }
}

export default ErrorBoundary

ErrorBoundary Component expanded :


function AsyncBoundary({
  pendingFallback,
  rejectFallback = ToastError,
  children,
  ...errorBoundaryProps
}) {
  return (
    <ErrorBoundary
      renderFallback={rejectFallback}
      {...errorBoundaryProps}
    >
      <SSRSuspense fallback={pendingFallback}>{children}</SSRSuspense>
    </ErrorBoundary>
  );
}

export default AsyncBoundary;

Test :

export default function Home() {
  return (
    <AsyncBoundary pendingFallback={<Loading/>}>
      <Test />
    </AsyncBoundary>
  );
}
function Test() {
  const { data } = useQuery(["documents"], getDocuments, {
    retry: false,
    suspense: true,
    useErrorBoundary: true
  })
  return (
    <div>test</div>
  );
}

export default Test;

But i found that error is thrown twice. and also fallback UI is render twice. I don't know why it happends. When i check with console in getDerivedStateFromError level, I can see that log appear twice even though api was called once. Ideas of how to get desired behavior are welcome. Thanks.

0 Answers
Related