Last active
March 22, 2024 05:41
-
-
Save ArcanisCz/a362d7d3d0da59742b79a1feabe8dea2 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