0

我收到“无法对未安装的组件执行 React 状态更新”。' 当我登录我的应用程序并重定向到主页时出错。

我正在使用 Context 来查看用户是否已登录,并每隔几分钟检查一次令牌是否仍然有效。

到目前为止,我将错误范围缩小到 AuthProvider 中的 logIn() 方法,但我不确定如何修复它 - 该组件始终安装,因此问题必须与 LoginForm 组件卸载有关。

这是重现错误的最小示例:

应用程序.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;

登录页面.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>
    );
  }
}

登录-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;

验证.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;
4

1 回答 1

0

删除多余setRedirect(true);login-component.tsx修复错误

于 2021-10-27T14:01:49.943 回答