3

I'm implementing my first react native project & it seems the best way to handle errors is with an app-level Error Boundary. I'm struggling to figure our how to integrate that with react-native-navigation. Current code looks like this:

# App.js

...

const startApp = () => {
  Navigation.startSingleScreenApp({
    screen: {
      screen: 'App.Splash',
      navigatorStyle: {
        navBarHidden: true,
      },
    },
  });
};

export function startTabs() {
  registerScreens(store, Provider);
  sagaMiddleware.run(RootSaga);

  loadIcons().then(() => {
    // Start app only if all icons are loaded
    startApp();
  });
}

startTabs();

And the screens.js:

# app/Screens.js

...

export default function registerScreens(store, Provider) {
  Navigation.registerComponent('App.Splash', () => SplashContainer, store, Provider);
  ...
 });

Because Navigation.startSingleScreenApp doesn't return a component, I'm struggling to figure out how to wrap an error boundary either immediately inside or outside the navigator. I tried scouring through react-native-navigation documentation, but couldn't find much help. Any ideas appreciated.

3 Answers 3

5

For the record, I solved this by wrapping the error boundary inside a parent provider, and passing that to each navigator screen. Eg:

// ProviderWithErrorBoundary.js

const ProviderWithErrorBoundary = ({ store, children }) => (
  <Provider store={store}>
      <ErrorBoundary>
        {children}
      </ErrorBoundary>
  </Provider>
);

Then passed then into my Screens.js via

// Screens.js
export default function RegisterScreens(store, Provider) {
  Navigation.registerComponent('App.Home', () => HomeContainer, store, Provider);
})

Hope this helps somebody

Sign up to request clarification or add additional context in comments.

1 Comment

Nice one as well! I didn't thought you can redefine Provider. Only one small limitation that I see: all screens must be wrapped with this custom Provider even if they don't benefit from it.
2

What I did when I had such requirement, I displayed Root HOC component, that wraps first screen, instead of actual first screen. Then you can handle errors inside Root, because it will be always loaded and use this.props.navigator of Root component to display errors, for example, with showModal().

Another benefit of having Root component that you can switch displayed root screen from side menu very easily naturally, without any special handling navigation actions. Or you can implement splash->login->home flow, like I did in the example below.

It can look like that:

class Root: Component {
  static propTypes = {
    navigator: PropTypes.instanceOf(Navigator).isRequired;
  }

  constructor(props) {
    this.state = { 
      content: <Splash navigator={this.props.navigator} onLoadComplete={this.handleLoadComplete} />,
    };
    // Adding network interceptor with handleNetworkError() as callback
  }
  
  handleLoadComplete = () => {
    this.setState({
      content: <Login navigator={this.props.navigator} onLoginComplete={this.handleLoginComplete} />,
    });
  }
  
  handleLoginComplete = () => {
    this.setState({ 
      content: <Home navigator={this.props.navigator} />,
    });
  }
  
  handleNetworkError = (error) => {
    this.props.navigator.showModal(screens.NetworkError, {
      passProps: { error },
    });
  }
  
  render() {
    return this.content;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Comments

1

I ended up wrapping each screen individually with my ErrorBoundary component. Not the most elegant or scalable option, perhaps, but it was quick, dirty, and easy, and for my use case it made the most sense.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.