Javascript 在React中延迟Auth0重定向,直到收到用户凭据

Javascript 在React中延迟Auth0重定向,直到收到用户凭据,javascript,reactjs,asynchronous,oauth,react-router,Javascript,Reactjs,Asynchronous,Oauth,React Router,我正在开发一个用于用户身份验证的React应用程序 目前的进程是: 用户单击主页上的Login按钮,将他们重定向到登录页面,在那里输入登录详细信息并提交表单 提交表单时,用户将使用Auth0登录(或正确处理错误),并重定向回主页 当应用程序刷新时,会调用一个自定义的handleAuthentication()函数,该函数解析URL哈希片段并设置用户会话,其中包括将访问令牌、到期时间和用户信息存储在localStorage中,以在刷新时提供持久性 回到主页后,登录按钮应替换为用户个人资料图像的化身

我正在开发一个用于用户身份验证的React应用程序

目前的进程是:

  • 用户单击主页上的
    Login
    按钮,将他们重定向到登录页面,在那里输入登录详细信息并提交表单
  • 提交表单时,用户将使用Auth0登录(或正确处理错误),并重定向回主页
  • 当应用程序刷新时,会调用一个自定义的
    handleAuthentication()
    函数,该函数解析URL哈希片段并设置用户会话,其中包括将访问令牌、到期时间和用户信息存储在
    localStorage
    中,以在刷新时提供持久性
  • 回到主页后,
    登录
    按钮应替换为用户个人资料图像的化身和他们个人资料页面的链接
  • 然而,虽然这个过程有效,但它并不总是在第一轮工作。有时我需要刷新页面,因为找不到用户信息。我发现原因是对
    auth0client.client.userInfo()
    的调用是异步的,因此在检索要存储在
    localStorage
    中的用户信息时会有一点延迟。因此,主页很可能在Auth0发送响应之前呈现。当我第二次刷新页面时,用户信息已被检索和存储,因此主页呈现正确

    以下是上述流程中的一些相关代码:

    auth.login()

    auth.handleAuthentication()

    auth.setSession()

    auth.getUserInfo()

    App.js

    export default function App() {
      auth.handleAuthentication();
    
      return (
          <BrowserRouter>
            <Suspense fallback={<p>Loading...</p>}>
              <Layout>
                <Switch>
                  // Routes to pages
                </Switch>
              </Layout>
            </Suspense>
          </BrowserRouter>
    
    导出默认函数App(){
    auth.handleAuthentication();
    返回(
    //到页面的路由
    
    auth
    是我创建的一个自定义类,它通过使用
    localStorage
    等扩展默认的Auth0功能

    App.js
    显示
    handleAuthentication()
    (扩展为,
    setSession()
    )在呈现新路由(本例中为主页)之前被调用。但是
    setSession()
    通常需要比页面呈现时间更长的时间才能完成。因此,当主页加载并调用
    auth.getUserInfo()时
    ,用户信息最初可能在
    localStorage
    中丢失,因此
    用户是未定义的
    错误,我大约有一半时间会收到该错误

    在做了一些研究之后,我想出了几个可能的解决方案

  • 使用超时延迟主页的呈现,直到用户信息存在于
    localStorage
    中,并同时显示加载页面。但我在其他答案中读到,您不应延迟呈现,因为这可能会导致其他问题。因此解决方案#2:
  • 最初在主页上显示占位符化身图像,直到用户信息在
    localStorage
    中可用。然后,使用用户信息更新状态,以重新渲染并显示用户的实际化身图像

  • 这两种方法中的任何一种都是好的/正确的方法吗?如果不是,还有什么其他方法可以用来解决这个问题?

    我会这样做:

    使用状态跟踪响应何时发生变化
    const[arrized,setarrized]=useState(false)

    将项目添加到
    localStorage
    后,在
    setSession()中更改它:

    this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
          if (err) {
            console.log("setSession: Couldn't get user info");
            return;
          } else {
            localStorage.setItem("user", JSON.stringify(user));
            // over here
            setArrived(true);
          }
        });
    
    并在
    useffect()中运行
    getUserInfo()


    谢谢@Gabriel Lupu,经过一些修改,这个解决方案成功了。我不得不在几个地方添加
    if(user==undefined)
    ,这样在
    useffect
    运行之前我就不会出错了。
    setSession(authResult) {
        //   Use the results from handleAuthentication() to set up the user's browser session
        let expiresAt = authResult.expiresIn * 1000 + new Date().getTime();
        this.accessToken = authResult.accessToken;
        this.idToken = authResult.idToken;
        this.expiresAt = expiresAt;
        localStorage.setItem("access_token", authResult.accessToken);
        localStorage.setItem("id_token", authResult.idToken);
        localStorage.setItem("expires_at", expiresAt);
        this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
          if (err) {
            console.log("setSession: Couldn't get user info");
            return;
          } else {
            localStorage.setItem("user", JSON.stringify(user));
          }
        });
      }
    
    getUserInfo() {
        //   Return user info
        const user = localStorage.getItem("user");
        if (!user) {
          console.log("getUserInfo: No user info to retrieve");
          return;
        }
        return JSON.parse(user);
      }
    
    export default function App() {
      auth.handleAuthentication();
    
      return (
          <BrowserRouter>
            <Suspense fallback={<p>Loading...</p>}>
              <Layout>
                <Switch>
                  // Routes to pages
                </Switch>
              </Layout>
            </Suspense>
          </BrowserRouter>
    
    this.auth0Client.client.userInfo(authResult.accessToken, (err, user) => {
          if (err) {
            console.log("setSession: Couldn't get user info");
            return;
          } else {
            localStorage.setItem("user", JSON.stringify(user));
            // over here
            setArrived(true);
          }
        });
    
    useEffect(() => {
        // run logic here to get the user from localStorage
        // I would also keep this information inside state
    }, [arrived])