Skip to content

Instantly share code, notes, and snippets.

@xdevmaycry
Forked from ArcanisCz/createProvider.js
Created May 5, 2020 07:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xdevmaycry/0150f0cd6fbc27464aca2a02c508af1b to your computer and use it in GitHub Desktop.
Save xdevmaycry/0150f0cd6fbc27464aca2a02c508af1b to your computer and use it in GitHub Desktop.
React Error Boundary, which can catch Component + Redux + Saga errors
/*
* Usage:
* const AppProvider = createProvider(rootReducer, rootSaga);
* ...
* <AppProvider>
* <AppComponent>
* </AppProvider>
*/
const createProvider = (reducer, saga) => {
const sagaMiddleware = createSagaMiddleware();
const middleware = compose(
applyMiddleware(sagaMiddleware),
window.devToolsExtension ? window.devToolsExtension() : x => x
);
class AppProvider extends React.Component {
constructor(props) {
super(props);
this.showError = this.showError.bind(this);
this.state = { error: null };
const catchingReducer = (state, action) => {
try {
return reducer(state, action);
} catch (e) {
console.error(e);
this.showError(e);
return state;
}
};
this.store = createStore(catchingReducer, middleware);
// .toPromise() is for redux-saga@1.0.0-beta.2, it has much nicer error stack
const sagaTask = sagaMiddleware.run(saga).toPromise();
sagaTask.catch(this.showError);
}
componentDidCatch(error) {
this.showError(error);
}
showError(error) {
/*
* This can be called even before component mounted, since there can be error in the first round of
* reducer when creating store. And we definitely dont want to create store as late as in componentDidMount.
* Hence, this small "helper" to simplify architecture. Which is no big deal,
* its used only for critical error state when app cannot continue anyway.
*/
if (this.updater.isMounted(this)) {
this.setState({error});
} else {
this.state = {error};
}
}
render() {
if (this.state.error) {
if (process.env.NODE_ENV === "development") {
return <RedBox error={this.state.error} />;
}
return "your production error message or component";
}
return <Provider {...this.props} store={this.store} />;
}
}
return AppProvider;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment