首页 > 解决方案 > React PrivateRoute 身份验证和未解决的令牌承诺问题

问题描述

我有一个想要为其创建 PrivateRoutes 的反应应用程序。以下是PrivateRoute.tsx文件:

import * as React from 'react';
import { Route,Redirect, RouteProps} from 'react-router-dom';
import { getToken } from '../../auth/auth';

interface PrivateRouteProps extends RouteProps {
  component?: any;
  children?: any;
}

const PrivateRoute = (props: PrivateRouteProps) => {
  const { component: Component, children, ...rest } = props;
  const [isAuthenticated, setAuth ] = useState(false);

  useEffect(() => {
    async function fetchToken() {
      try {
        const token = await getToken();
    
        if (token && token.length) {
          setAuth(true);
        } else {
          setAuth(false);
        }
       } catch(e) {
         console.log(e);
         setAuth(false);
       }
    }
    fetchToken();
  }, [isAuthenticated]);

  return (
    <Route
      {...rest}
      render={routeProps =>
        isAuthenticated ? (
          Component ? (
            <Component {...routeProps} />
          ) : (
            children
          )
        ) : (
          <Redirect
            to={{
              pathname: '/signin',
              state: { from: routeProps.location },
            }}
          />
        )
      }
    />
  );
};

export default PrivateRoute;

以下是我在 App.tsx 文件中的路由设置

//...
const App = () => {
  return (
    <div className="application">
        <Router>
          <Switch>
            <Route path="/signin" component={SignIn} />
            <Route path="/signup" component={SignUp} />
            <NavBar>
              <Switch>
                <PrivateRoute path="/tasks" component={Tasks}/>
                <PrivateRoute path="/people" component={People}/>
              </Switch>
            </NavBar>
            <Route component={NotFound} />
            <Redirect from="/" to="/signin" exact={true} />
          </Switch>
        </Router>
    </div>
  );
};

export default App;

令牌存储在 LocalForage 中。上面的代码产生以下警告,我无法访问 PrivateRoutes。我怀疑这是因为组件在承诺得到解决并且令牌可用之前被返回。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

我会感谢有用的答案。

标签: reactjsreact-routerreact-router-domreact-typescript

解决方案


尝试在令牌获取未完成时添加某种加载器,因为您的PrivateRoute立即返回Redirect会将您重定向到另一个组件,但是由于您尚未取消您的承诺,一旦完成,它将调用实际上未安装的加载器,这将setAuth导致PrivateRoute你有这个问题。

例子:

import * as React from 'react';
import { Route,Redirect, RouteProps} from 'react-router-dom';
import { getToken } from '../../auth/auth';

interface PrivateRouteProps extends RouteProps {
  component?: any;
  children?: any;
}

const PrivateRoute = (props: PrivateRouteProps) => {
  const { component: Component, children, ...rest } = props;
  const [isAuthenticated, setAuth ] = useState(false);
  const [isAuthenticating, setIsAuthenticating] = useState(true);

  useEffect(() => {
    async function fetchToken() {
      try {
        setIsAuthenticating(true);
        const token = await getToken();
    
        if (token && token.length) {
          setAuth(true);
        } else {
          setAuth(false);
        }
       } catch(e) {
         console.log(e);
         setAuth(false);
       } finally {
           setIsAuthenticating(false);
       }
    }
    fetchToken();
  }, [isAuthenticated]);

  if (isAuthenticating) {
      return <span>Loading...</span>
  }

  return (
    <Route
      {...rest}
      render={routeProps =>
        isAuthenticated ? (
          Component ? (
            <Component {...routeProps} />
          ) : (
            children
          )
        ) : (
          <Redirect
            to={{
              pathname: '/signin',
              state: { from: routeProps.location },
            }}
          />
        )
      }
    />
  );
};

export default PrivateRoute;

推荐阅读