react-native: componentDidCatch() doesn't catch native errors

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

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

Steps to Reproduce

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>
    );
  }
}

Expected Behavior

After dismissing the red screen (which would only appear in dev), the component should display: Something went wrong

Actual Behavior

After dismissing the red screen, nothing is shown. I also tried to use console.log() in my ErrorBoundary’s render(), but nothing gets logged,

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 5
  • Comments: 17 (5 by maintainers)

Most upvoted comments

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.

@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?

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.

Any update on this please ?

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",

Yep, sorry about that.

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.

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?