I'm implementing a Markdown renderer, and in some unhandled edge cases, I end up rendering a <View> inside a <Text>, which of course fails with the error: "Views nested within a Text must have a width and height.
Now I'm trying to catch this error using componentDidCatch() to avoid any crashes in production, and to present a nice error message asking the user to fill a bug with the reproduce case. Unfortunately, componentDidCatch doesn't seem to catch this particular error.
Environment:
OS: macOS Sierra 10.12.6
Node: 9.5.0
Yarn: 1.5.1
npm: 5.6.0
Watchman: 4.7.0
Xcode: Xcode 9.0 Build version 9A235
Android Studio: 3.0 AI-171.4443003
Packages: (wanted => installed)
react: 16.2.0 => 16.2.0
react-native: 0.52.0 => 0.52.0
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
console.log('We did catch', error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <Text>Something went wrong.</Text>;
}
return this.props.children;
}
}
class CommentListItemComponent extends Component {
render() {
return (
<ErrorBoundary>
<Text>
<View>
<Text>No width and height, will crash</Text>
</View>
</Text>
</ErrorBoundary>
);
}
}
After dismissing the red screen (which would only appear in dev), the component should display: _Something went wrong_
After dismissing the red screen, nothing is shown.
I also tried to use console.log() in my ErrorBoundary's render(), but nothing gets logged,
Thanks for posting this! It looks like your issue may refer to an older version of React Native. Can you reproduce the issue on the latest release, v0.54?
Thank you for your contributions.
My bad, I dunno why I thought 0.52 was the last version 馃槺
For what it's worth, I tried with 0.53, it still failed.
But it works with 0.54 馃帀
Sorry, spoke too soon. This works perfectly on iOS but doesn't work on Android.
Android displays the following error: "Unexpected view type nested under text node: class com.facebook.react.uimanager.LayoutShadowNode", then a blank screen when I dismiss the popup.
A Text within a Text is not a use case we plan on supporting. It does happen to work on iOS but it's not intentional and this behavior might be changed to match what happens on Android at a future time.
I do realize the docs encourage this type of use. I need to follow up with the rest of my team to determine if the docs need to be updated to remove this recommendation.
@hramos I think you misread my problem.
I'm fine with not being able to nest a View inside a Text. My problem is componentDidCatch not being fired in that case.
Shouldn't it be the case?
Yep, sorry about that.
The "Old Version" label should be removed, as this issue is confirmed with last stable release.
I would love to work on resolving this, but I would need some help getting started. Anyone wants to mentor me?
Any updates about this issue? I really need that fix :)
My problem is with a lib react-native-markdown-view. In the known issues they have something like:
We can not render properly the nested lists
So I thought that this is the perfect case to use the componentDidCatch. I've tried to put componentDidCatch on all levels of the app rendering tree, but none of them fires.
"react": "^16.4.0",
"react-native": "^0.55.4",
"react-native-markdown-view": "^1.1.4",
componentDidCatch only catches javascript errors - the error you're trying to catch is a native error. You can gracefully catch native errors using https://github.com/master-atul/react-native-exception-handler however the app will be crashed at that point and will need to be restarted.
You could possibly wrap react-native-markdown-view in your own component that detects views inside text.
I do think this is a react-native issue that should be solved. react-native modules that supply native bridges should handle likely native crashes that occur due to bad data be passed by either validating the data in js side or catching the exception in the native exception. Text should do the same.
Any update on this please ?
Any update ?
i can catch the error but seems it will not render the plan B ui in my ErrorBoundary
I see this is still open and sounds like there may be a change to react-native to fix an underlying issue, but if you're hitting a similar problem and want to get around it, you could try using static getDerivedStateFromError instead of componentDidCatch. It's not the exact same thing, but might help you along. Doing so will allow you to both log the error and display a fallback UI.
A similar example is shown in the official docs
And we could modify the example in this PR description as follows:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
console.log('We did catch', error);
return { hasError: true };
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <Text>Something went wrong.</Text>;
}
return this.props.children;
}
}
class CommentListItemComponent extends Component {
render() {
return (
<ErrorBoundary>
<Text>
<View>
<Text>No width and height, will crash</Text>
</View>
</Text>
</ErrorBoundary>
);
}
}
One thing to note is that static getDerivedStateFromError only receives a single error argument, not the second info argument like componentDidCatch.
Again, this isn't a fix for any potential issue with componentDidCatch only a possible workaround. It's what I'm using in an RN app.
componentDidCatch only catches javascript errors - the error you're trying to catch is a native error. You can gracefully catch native errors using https://github.com/master-atul/react-native-exception-handler however the app will be crashed at that point and will need to be restarted.
Is this documented somewhere and is it an issue that could theoretically be solved?
This is by design. Crashes on the native side may leave the app in an inconsistent state and the only option is to crash and restarted. I do not foresee the behavior of componentDidCatch changing as not all native errors could even be handled. For example, if an app runs out of memory, we could not catch native errors. So by design, if we implemented this, we could only catch a subset of known errors that are safe to recover from. In that case it's likely better to turn those crashes into warnings during development time or change things around so that people will never run into those issues in the first place.
Hey everyone - isn't the reason that the catch doesn't work because of the fact that it catches the errors from it's child components?
Take a look at this CodePen here: https://codepen.io/sgroff04/pen/dVbgJy/
In it, there is a button called _BuggyButton_ that throws an error when clicked (through _handleClick_), which bubbles up to the parent component wrapping it called ErrorBoundary, which in the render function itself chooses what fallback UI to display.
So in order to really understand this, wouldn't we need to take a look at the
From my understanding, how would either the
Edit: Also check this link which clarifies this: https://stackoverflow.com/questions/47223765/componentdidcatch-does-not-work
Most helpful comment
componentDidCatch only catches javascript errors - the error you're trying to catch is a native error. You can gracefully catch native errors using https://github.com/master-atul/react-native-exception-handler however the app will be crashed at that point and will need to be restarted.
You could possibly wrap react-native-markdown-view in your own component that detects views inside text.
I do think this is a react-native issue that should be solved. react-native modules that supply native bridges should handle likely native crashes that occur due to bad data be passed by either validating the data in js side or catching the exception in the native exception. Text should do the same.