Comments (16)
We're implementing a new fallbackRender
prop which will allow you to do whatever you'd like:
<ErrorBoundary fallbackRender={props => <YourErrorFallback {...props} your="extra props" />}>
...
</ErrorBoundary>
from react-error-boundary.
What stops you from passing an inline function component currently?
const _Uploader = lazy(() => import("uploader"));
type Props = { onRequestClose: () => void };
const Uploader: SFC<Props> = props => (
<ErrorBoundary
FallbackComponent={({ error }) => (
<MyErrorComponent error={error} onRequestClose={onRequestClose} />
)}
>
<Suspense fallback={<MyLoadingComponent {...props} />}>
<_Uploader {...props} />
</Suspense>
</ErrorBoundary>
);
Here's an example:
https://codesandbox.io/s/zk469wp6jp
from react-error-boundary.
This is a very nuanced topic. As I mentioned in my comment right above, I've discussed this in depth on a recent GitHub issue. Rather than repeat it all, here you go:
from react-error-boundary.
Wouldn't that have poor performance? The fallback component reference will be changing identity with every render of Uploader
, which would cause it to remount unnecessarily?
Render props don't have that issue as they bypass calling React.createElement
.
from react-error-boundary.
Creating an inline function is fast. People do that in tons of places. Rendering ErrorBoundary
is fast too. Unless there's an error, it just passes through props.children
.
But if you have concerns about recreating this component, you can memoize it 😄
https://codesandbox.io/s/w7v038y1r5
from react-error-boundary.
My concern is not about creating functions, but rather about React remounting a component needlessly (because it's reference identity is changing)—unless I misunderstand.
Thanks for the memoizing example, that makes sense. Unfortunately it's awkward because every time message
changes, we'll create a whole new component, which will lead to a remount, when it should really only lead to an update of the same component.
My concern about remounts isn't just about performance, but also any DOM state, like input
values or focus. Remounting will lose/reset that state?
from react-error-boundary.
Render props don't have that issue as they bypass calling
React.createElement
.
I don't think your real complaint here is with render props vs React elements. I think it's with the ability to pass arbitrary custom props along.
Either way render props are called (as vanilla functions or wrapped in createElement
) you would need a wrapper with inline scope, or a memoized approach like I linked above, to pass additional, custom props. I don't really feel strongly about not supporting custom props with ErrorComponent
, but I also don't think it's necessary. This component is a lightweight example of how an Error Boundary can work. It's not all that useful in itself. 😄
But as far as render props (functions) vs React elements, I think React elements are a more useful pattern because they are more flexible for users. (You can pass a function component or a class component, your component can use "hooks", etc.) They also fit into React's concurrent rendering model a bit better, since React can decide if it should process the components now or wait until the next frame.
from react-error-boundary.
Unfortunately it's awkward because every time message changes, we'll create a whole new component
I think this is micro-optimizing. How expensive is this "whole new component"? It's really just a tiny function that returns a React element. It's like recreating an inline click event handler.
which will lead to a remount, when it should really only lead to an update of the same component.
Why would it lead to a remount? The only thing that would remount in this case would be your error message. If that's shown, your app is in a failure state. (And also the inline message prop seems unlikely to actually change in this case.)
from react-error-boundary.
only thing that would remount in this case would be your error message
That was my understanding.
Re. performance, I agree! However I think the point about losing DOM state (e.g. focus on an inner button) due to remounts is more worrying, as that could be bad UX/accessibility—albeit it's quite unlikely you'll have much going on inside of an error fallback component, but ideally we wouldn't have to make that assumption.
from react-error-boundary.
However I think the point about losing DOM state (e.g. focus on an inner button) due to remounts is more worrying
Just to be clear, the children you wrap inside of your error boundary- in the normal (non-errored) state– would not remount or be impacted by this. The only thing that would remount would be your fallback UI, in which case...your app is broken. It can't recover. (The ErrorBoundary
component in this lib doesn't provide a way for you to reset its state and render non-fallback UI once it's been triggered.) So I'm still not understanding what the concrete concern is here.
I think fallback components are usually static overlays, but...assuming you had some form elements in there that were stateful– under what conditions would your onRequestClose
prop change to recreate the fallback component? I feel like we're talking about a very unlikely hypothetical here.
from react-error-boundary.
under what conditions would your
onRequestClose
prop change to recreate the fallback component?
Wouldn't the fallback component also be recreated every time Uploader
is called? And that could happen any number of times (with each re-render of the parent), assuming Uploader
is not memoized.
If Uploader
was memoized (using PureComponent
or React.memo
), my understanding is that the fallback component would only be recreated if the props changed. In this case, that's just onRequestClose
.
Is my understanding correct? If so, the former scenario seems not so unlikely to me. Of course it's easy to make it memoized, but is that an assumption/requirement we want to bake in to this library?
(Thanks for helping me understand this!)
from react-error-boundary.
Wouldn't the fallback component also be recreated every time
Uploader
is called? And that could happen any number of times (with each re-render of the parent), assumingUploader
is not memoized.
Why would this matter? Again, this "component" is a very small function, not unlike a click handler. Recreating it is fast.
Thanks for helping me understand this!
No problem. It's an interesting discussion. :)
from react-error-boundary.
If the fallback component is recreated (fast so not a problem in itself), it will be remounted (fast so not a problem in itself). In turn, the remount would mean any DOM state of the fallback component will be lost (e.g. an inner input
's value or a button
's focus). This is my concern.
Initially I thought recreating + remounting components needlessly was a performance issue, but the more I've given it thought—and after you clarified the situation as negligible—now my hesitation is around trying to avoid bad UX or accessibility issues.
Of course there are many scenarios where this won't be an issue (most of the time, we presume the fallback component will be a simple error message).
from react-error-boundary.
It's funny because I'm having a similar conversation in another repo with someone else this morning (bvaughn/react-window/issues/85)
In this case of this specific library, I don't feel very strongly about any particular API decision. I didn't think this component would get much use when I created it. I thought it would just be an example to reference.
If you'd like to submit a PR that changes the component to pass through props in a way similar to this, I wouldn't really object:
render() {
const {children, FallbackComponent, ...rest} = this.props;
const {error, info} = this.state;
if (error !== null) {
return (
<FallbackComponent
{...rest}
componentStack={
// istanbul ignore next: Ignoring ternary; can’t reproduce missing info in test environment.
info ? info.componentStack : ''
}
error={error}
/>
);
}
return children;
}
from react-error-boundary.
Sorry to interrupt. I have opened an issue on reactjs.org to seek for clarification on the render props documentation. I was told (and convinced) that render props is a better pattern because that would not trigger re-mount when inlining (see example at reactjs/react.dev#1241 (comment)). But reading your discussion makes me feel the opposite.
Is there no universally better pattern? Can you shed some light on this?
from react-error-boundary.
🎉 This issue has been resolved in version 2.0.0 🎉
The release is available on:
npm package (@latest dist-tag)
- GitHub release
Your semantic-release bot 📦🚀
from react-error-boundary.
Related Issues (20)
- 'ErrorBoundaryContext not found' appears when using useErrorBoundary HOT 12
- Error when rendering inside a server component in Next.js HOT 7
- 'ErrorBoundary' cannot be used as a JSX component. HOT 10
- Reset error state on router changed HOT 2
- [New feature request] add `ErrorBoundaryGroup` like @suspensive/react HOT 2
- [Proposal] Propagate original error when no fallback was provided HOT 5
- 4.0.11 cannot find module 'react-error-boundary' or its corresponding type declarations. HOT 1
- [Proposal] Detect an infinite loop of resetting the error HOT 4
- type ErrorBoundaryPropsWithFallback allows fallback to be null HOT 4
- How to customize error HOT 3
- NPM Install Fails with 404 for 'react-rerror-bounday' Package HOT 4
- Preventing React unmounting UI on error? HOT 3
- useErrorBoundary as global HOT 2
- doesn't catch errors thrown by new Error('error text') but catches errors thrown by throw 'error text' HOT 1
- 'ErrorBoundary' cannot be used as a JSX component. HOT 3
- Getting children of ErrorBoundary in render functions HOT 1
- Bug with catching errors when using React Router HOT 1
- `fallback` function is not allowing to render `ReactPortal` via `createPortal()` function HOT 3
- Trying to access an eslint configuration that is not a dependency of react-error-boundary HOT 4
- "use client" not appearing in the ESM entry HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-error-boundary.