<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong></p>
<p dir="auto">Bug</p>
<p dir="auto"><strong>What is the current behavior?</strong></p>
<p dir="auto">In React 15, render errors which killed execution of the app would leave the existing HTML on the page. In React 16, the existing HTML gets wiped (the "white screen of death").</p>
<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">It would be a <em>much better</em> user experience if we could configure it so the existing HTML remained if render failed. App functionality would fail, but the page would still be there, and users could use standard HTML links etc to continue navigating. In some cases they may not even notice that the app broke.</p>
<p dir="auto">I'm aware of Error Boundaries as a proposed solution for this in React 16. However, these do not seem like a great solution for us for two reasons:</p>
<ol dir="auto">
<li>We'd need to pepper a lot of them across the entire codebase to get reasonable granularity and restrict the impact of errors, for example to a <code class="notranslate">&lt;StickySidebar&gt;</code> on an <code class="notranslate">&lt;Article&gt;</code> or whatever. This is a major code change for an app which might have hundreds of components.</li>
<li>Even if we did the above, we'd get that segment of the app (which may be significant) replaced by an error message. What if there's an unexpected error in <code class="notranslate">&lt;ArticleBody&gt;</code>? That's the entire purpose of the page, replaced by an error message. Far better for us to stop JS execution and leave the user with static HTML.</li>
</ol>
<p dir="auto">Obviously, bugs in our app are our fault and we should fix them. But they're not always predictable: for example, today we tracked down a bug to <code class="notranslate">localStorage.setItem</code> throwing an exception only on Safari 10- in Private Browsing mode. That is a tough issue to anticipate. It's difficult to ensure the app is bug-free, and if we miss something, the outcome in React 16 is catastrophic instead of merely a reduction of the user experience.</p>
<p dir="auto">Here's a demo in React 15: <a href="https://codepen.io/giles-v/pen/GdRyBX" rel="nofollow">https://codepen.io/giles-v/pen/GdRyBX</a><br>
Here's the same code in React 16: <a href="https://codepen.io/giles-v/pen/xjxYEY" rel="nofollow">https://codepen.io/giles-v/pen/xjxYEY</a></p>
<p dir="auto">I wasn't sure where to report this, but this is a problem I'm having with a new feature.</p>
<p dir="auto">I just finished upgrading my team to React 16. Overall, I think the upgrade is great. We are using fragments and the relaxed constraints on what you can return from render(), and I'm overall very happy with it.</p>
<p dir="auto">My only issue is with error boundaries. The feature seems to be well-intended, and does help out quite a bit. The improved error reporting especially is beautiful and will make debugging a dream.</p>
<p dir="auto">The problem is that I believe we are leaving our users in a worse state by having to display fallback UIs. In a perfect world, we would have no client side errors and none of this would even be a discussion. But unfortunately we do have to deal with client-side errors. I agree that leaving the UI in an unpredictable state is less than desired, but I would argue that it's still better than taking away the UI completely. If a user triggers a client-side error, but the UI is still there, they can continue to use the site with little-to-no issue in the case of <em>most</em> errors. But with React 16's new functionality, even the smallest of errors will unmount the UI.</p>
<p dir="auto">Our options are:</p>
<ul dir="auto">
<li>Go with the easy route and implement a top-level error boundary that will unmount the whole UI, replacing it with a fallback that does nothing for the user.</li>
<li>Take significant developer time to implement fine-grained error boundaries that will still leave most of the UI untouched, only replacing components in error. But overall, this will still be taking functionality away from the user.</li>
</ul>
<p dir="auto">Either way, with this new functionality, we need to have at least a top-level error boundary to display <em>something</em> to the user. Our top-level boundary still displays our navigation bar so that the user can still navigate away from the page and use other parts of the site. The alternative is that they will need to refresh the page because everything will be unmounted.</p>
<p dir="auto">I agree that displaying a fallback UI can be useful in instances where you <em>expect</em> an error in some cases (for example, when loading an image from a third party CDN or something). But in cases where a bug is producing an <em>unexpected</em> error, we should still be able to keep the UI in its previous state.</p>
<p dir="auto">This is how I envision it working:</p>
<ul dir="auto">
<li>Error boundaries are still exactly as they are today, except...</li>
<li>If the error was thrown inside the render() of a component, that component will either not be mounted (if it hasn't yet been mounted) or be left in its prior state (if it has already been successfully mounted). The parent of the offending component and all of the parent's other children are still rendered.</li>
<li>If the error was thrown inside a lifecycle method, the offending component's tree is left as it was, and other children of its parent can still be updated.</li>
<li>Error boundaries can <em>still</em> display a fallback UI if they want. componentDidMount() still has the ability to set state.</li>
</ul>
<p dir="auto">If you are handling an <em>expected</em> error, you should display a fallback UI. If you are handling an <em>unexpected</em> error, you should try to leave the UI in the most unbroken state possible for the user. The error should still be reported and caught by a top-level error boundary so that it can be logged, but the UI should not need to be replaced in all instances.</p>
<p dir="auto">Perhaps I'm missing out on a standard process for handling these problems I'm talking about, and I am happy to hear what other people are doing to get around this, but I believe this feature as it exists today means more work for developers, and poor functionality for users.</p>