我得到了'不能在卸载的组件上执行React状态更新'。当我登录到我的应用程序并重定向到主页时出现错误。
我使用上下文来查看用户是否登录,并每隔几分钟检查令牌是否仍然有效。
到目前为止,我把错误缩小到AuthProvider的logIn()方法,但我不知道如何修复它-这个组件在任何时候都是挂载的,所以问题一定是与LoginForm组件被卸载。
下面是重现错误的最小示例:App.tsx
const App = () => {
return (
<div className="App">
<AuthProvider>
<HashRouter>
<Routes />
</HashRouter>
</AuthProvider>
</div>
);
};
const Routes = () => {
const Auth = React.useContext(AuthContext);
return (
<Switch>
<ProtectedRoute path={"/home"} auth={Auth.isAuthenticated} component={HomePage} />
<ProtectedLogin path={"/"} auth={Auth.isAuthenticated} component={LoginPage} />
<Redirect to="/" />
</Switch>
);
};
const ProtectedRoute = ({ auth, component: Component, ...rest }: any) => {
return <Route {...rest} render={() => auth ? (<Component />) : (<Redirect to="/"/>)} />;
};
const ProtectedLogin = ({ auth, component: Component, ...rest }: any) => {
return <Route {...rest} render={() => !auth ? (<Component />) : (<Redirect to="/home"/>)} />;
};
export default App;
login-page.component.tsx
export default class LoginPage extends Component<IProps, IState> {
render(): ReactElement {
return (
<div className="container card-wrapper">
<div className="card mt-5 login">
<div className="card-body p-5">
<LoginForm />
</div>
</div>
</div>
);
}
}
login-form.component.tsx
const LoginForm = () => {
const [redirect, setRedirect] = useState(false);
const Auth = React.useContext(AuthContext);
if (redirect) {
return <Redirect to="/home" />;
}
return (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={(formValues: FormikValues) => {
ApiService.post("user/authenticate", formValues)
.then((res: any) => {
Auth.logIn({token: res.token});
Auth.initTokenChecking();
setRedirect(true);
})
.catch(() => console.log('error'));
}}
validationSchema={Yup.object().shape({
email: Yup.string(),
password: Yup.string()
})}
>
{(props) => {
const {
values,
isSubmitting,
handleChange,
handleSubmit,
} = props;
return (
<div>
<form className="form-group mb-3" onSubmit={handleSubmit}>
<div className="mb-4">
<VWTextInputField
required={true}
label="E-mail"
name="email"
value={values.email}
onChange={handleChange}
/>
</div>
<div className="mb-4">
<VWPasswordField
required={true}
label="Password"
name="password"
value={values.password}
onChange={handleChange}
/>
</div>
<div className="d-grid">
<button
type="submit"
className="btn btn-block btn-primary"
disabled={isSubmitting}
>
Log in
</button>
</div>
</form>
</div>
);
}}
</Formik>
);
};
export default LoginForm;
auth.jsx
const AuthContext = React.createContext();
export class AuthProvider extends Component {
_interval = null;
state = {
isAuthenticated: false,
user: null,
};
logIn = (user) => {
this.setState({ user, isAuthenticated: true });
localStorage.setItem("token", JSON.stringify(user.token));
};
logOut = () => {
if (this._interval) {
clearInterval(this._interval);
}
this.setState({ user: null, isAuthenticated: false });
localStorage.clear();
};
initTokenChecking = () => {
this._interval = setInterval(() => {
if (!localStorage.getItem("token")) {
this.logOut();
}
const token = JSON.parse(localStorage.getItem("token"));
console.log(jwt_decode(token));
if (jwt_decode(token).exp < Date.now() / 1000) {
this.logOut();
}
}, 2 * 60 * 1000);
};
render() {
const { user, isAuthenticated } = this.state;
const { logIn, logOut, initTokenChecking } = this;
return (
<AuthContext.Provider
value={{
user,
isAuthenticated,
logIn,
logOut,
initTokenChecking,
}}
>
{this.props.children}
</AuthContext.Provider>
);
}
}
export default AuthContext;
删除login-component.tsx
中冗余的setRedirect(true);
修复错误