-
-
Save xdevmaycry/0150f0cd6fbc27464aca2a02c508af1b to your computer and use it in GitHub Desktop.
React Error Boundary, which can catch Component + Redux + Saga errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 [email protected], 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