#javascript #reactjs #error-handling
#javascript #reactjs #обработка ошибок
Вопрос:
Я пытаюсь создать свою собственную ошибку ErrorBoundary, чтобы перехватывать все приложения и регистрировать их где-нибудь. В настоящее время я использую панель закусок MaterialUI для отображения ошибок. Однако компонент ErrorBoundary регистрирует ошибку, но приложение все равно выходит из строя.
Вот gif-файл того, что я пытаюсь описать.
Мой код для страницы входа в систему:
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
error: { isPresent: false, message: {} },
password: '',
email: '',
validInput: false,
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
static contextType = UserDispatchContext
componentDidUpdate(prevProp, prevState) {
this.validateForm();
}
validateForm() {
let valid = this.state.email.length > 0 amp;amp; this.state.password.length > 0;
if (valid !== this.state.validInput) {
this.setState({ validInput: valid });
}
}
async handleSubmit(e) {
//e.preventDefault();
const { dispatch } = this.context
const response = await callApi({
path: "/auth/local", method: "POST", body: {
identifier: this.state.email,
password: this.state.password
}
})
if (response.user) {
dispatch({ type: "LOGIN", user: response.user })
} else {
const error = { isPresent: true, message: response }
this.setState({ error })
}
}
handleChange = (prop) => (event) => {
this.setState({[prop]: event.target.value });
};
render() {
const { classes } = this.props;
if (this.state.error.isPresent) {
throw this.state.error.message
}
return (
<div style={{ width: "100%", height: "100%", display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<ReactTitle>Login</ReactTitle>
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<SvgIcon>
{coffeeBeans}
</SvgIcon>
</Avatar>
<Typography component="h1" variant="h5">
Login
</Typography>
<form className={classes.form}>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
value={this.state.email}
onChange={this.handleChange('email')}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
value={this.state.password}
onChange={this.handleChange('password')}
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
</Grid>
</Grid>
<Button
fullWidth
variant="contained"
color="primary"
className={classes.submit}
disabled={!this.state.validInput}
onClick={() => this.handleSubmit()}
>
Login
</Button>
<Grid container justify="flex-end">
<Grid item>
<Link
to="/signup"
variant="body2">
New user? Sign up
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={5}>
<Copyright />
</Box>
</Container>
</div>
)
}
}
И ошибка:
class ErrorHandler extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, open: false, message: {} };
}
componentDidCatch(error, info) {
this.setState({ hasError: true, open: true, message: error });
console.log("error", error);
}
handleClose() {
this.setState({ hasError: false, open: false })
}
parseObjectProperties(obj, parse) {
for (var k in obj) {
if (typeof obj[k] === 'object' amp;amp; obj[k] !== null) {
this.parseObjectProperties(obj[k], parse)
} else if (obj.hasOwnProperty(k)) {
parse(k, obj[k])
}
}
}
getErrorMessage(errorObject) {
var message = "";
this.parseObjectProperties(errorObject, function (k, prop) {
if (k === "message")
message = prop
})
return message;
}
render() {
if (this.state.hasError) {
return (
<>
{this.props.children}
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
open={this.state.open}
onClose={this.handleClose}
autoHideDuration={4000}
>
<Alert onClose={this.handleClose} severity="error">
{this.getErrorMessage(this.state.message)}
</Alert>
</Snackbar>
</>
)
}
return this.props.children;
}
}
Редактировать: я забыл ту часть, где я окружаю свои страницы ошибкой ErrorBoundary.
<Router>
<Header />
<Content >
<ErrorHandler>
<Switch>
<PublicRoute exact path="/" component={Home} />
<PublicRoute restricted path="/login" component={Login} />
<PrivateRoute path="/profile" component={Profile} />
<PublicRoute restricted path="/signup" component={SignUp} />
</Switch>
</ErrorHandler>
</Content>
</Router>
Я не знаю, что я делаю не так. Кто-нибудь знает, что я делаю не так?
Ответ №1:
Вам не хватает getDerivedStateFromError
в вашей границе ошибки, которая обновит ErrorHandler
состояние и отобразит Snackbar
. Ознакомьтесь с документами react для получения дополнительной информации о границах ошибок.
class ErrorHandler extends React.Component {
// ...
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error }
}
render() {
if (this.state.hasError) {
return (
<>
{this.props.children}
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
open={this.state.open}
onClose={this.handleClose}
autoHideDuration={4000}
>
<Alert onClose={this.handleClose} severity="error">
{this.getErrorMessage(this.state.message)}
</Alert>
</Snackbar>
</>
)
}
return this.props.children;
}
}