简体   繁体   English

使用 aws-amplify 作为身份验证的 PrivateRoute 功能组件

[英]PrivateRoute functional component using aws-amplify as authentication

I'm trying to create a functional component equivalent of the following PrivateRoute class component (source code here ):我正在尝试创建一个等效于以下 PrivateRoute 类组件的功能组件(源代码在这里):

import React, { useState, useEffect } from "react";
import { Route, Redirect, withRouter, useHistory } from "react-router-dom";
import { Auth } from "aws-amplify";

class PrivateRoute extends React.Component {
  state = {
    loaded: false,
    isAuthenticated: false
  };
  componentDidMount() {
    this.authenticate();
    this.unlisten = this.props.history.listen(() => {
      Auth.currentAuthenticatedUser()
        .then(user => console.log("user: ", user))
        .catch(() => {
          if (this.state.isAuthenticated)
            this.setState({ isAuthenticated: false });
        });
    });
  }
  componentWillUnmount() {
    this.unlisten();
  }
  authenticate() {
    Auth.currentAuthenticatedUser()
      .then(() => {
        this.setState({ loaded: true, isAuthenticated: true });
      })
      .catch(() => this.props.history.push("/auth"));
  }
  render() {
    const { component: Component, ...rest } = this.props;
    const { loaded, isAuthenticated } = this.state;
    if (!loaded) return null;
    return (
      <Route
        {...rest}
        render={props => {
          return isAuthenticated ? (
            <Component {...props} />
          ) : (
            <Redirect
              to={{
                pathname: "/auth"
              }}
            />
          );
        }}
      />
    );
  }
}

export default withRouter(PrivateRoute);

The above code works in my application when I use it like so:当我像这样使用它时,上面的代码在我的应用程序中工作:

<PrivateRoute
  exact
  path={urls.homepage}
  component={Homepage}
/>

My attempt at a converting the above class component into a functional component is the following:我将上述类组件转换为功能组件的尝试如下:

import React, { useState, useEffect } from "react";
import { Route, Redirect, useHistory } from "react-router-dom";
import { Auth } from "aws-amplify";

const PrivateRoute = ({ component: Component, ...rest }) => {
  const [isLoaded, setIsLoaded] = useState(false);
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  let history = useHistory();

  useEffect(() => {
    Auth.currentAuthenticatedUser()
      .then(() => {
        setIsLoaded(true);
        setIsAuthenticated(true);
      })
      .catch(() => history.push("/auth"));

    return () =>
      history.listen(() => {
        Auth.currentAuthenticatedUser()
          .then(user => console.log("user: ", user))
          .catch(() => {
            if (isAuthenticated) setIsAuthenticated(false);
          });
      });
  }, [history, isAuthenticated]);

  if (!isLoaded) return null;

  return (
    <Route
      {...rest}
      render={props => {
        return isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/auth"
            }}
          />
        );
      }}
    />
  );
};

export default PrivateRoute;

But when using my functional component in the same way, I keep getting the following error:但是当以同样的方式使用我的功能组件时,我不断收到以下错误:

Warning: Can't perform a React state update on an unmounted component.警告:无法对卸载的组件执行 React 状态更新。 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修复,取消 useEffect 清理函数中的所有订阅和异步任务

It always redirects me to /auth, regardless of whether I am logged in or not.它总是将我重定向到 /auth,无论我是否登录。 What am I doing wrong?我究竟做错了什么? Any help is much appreciated!任何帮助深表感谢!

I think you are missing your unmount, the return in the useEffect should be your unlisten which is the unmount.我认为您错过了卸载, useEffect的返回应该是您的unlisten ,即卸载。 Also, I removed useHistory and pulled history from the props and used withRouter另外,我删除了useHistory并从道具中提取了history并使用了withRouter

Try this尝试这个

import React, { useState, useEffect } from "react";
import { Route, Redirect, withRouter } from "react-router-dom";
import { Auth } from "aws-amplify";

const PrivateRoute = ({ component: Component, history, ...rest }) => {
  const [isLoaded, setIsLoaded] = useState(false);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    Auth.currentAuthenticatedUser()
      .then(() => {
        setIsLoaded(true);
        setIsAuthenticated(true);
      })
      .catch(() => history.push("/auth"));
    
    const unlisten = history.listen(() => {
      Auth.currentAuthenticatedUser()
        .then(user => console.log("user: ", user))
        .catch(() => {
          if (isAuthenticated) setIsAuthenticated(false);
        });
    });

    return unlisten();
  }, [history, isAuthenticated]);

  if (!isLoaded) return null;

  return (
    <Route
      {...rest}
      render={props => {
        return isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/auth"
            }}
          />
        );
      }}
    />
  );
};

export default withRouter(PrivateRoute);

Try this out:试试这个:

useEffect(() => {
  async function CheckAuth() {
    await Auth.currentAuthenticatedUser()
      .then((user) => {
        setIsLoaded(true);
        setIsAuthenticated(true);
      })
    .catch(() => history.push("/auth"));
  }
  CheckAuth();
}, []);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM