当前位置: 首页 > 面试题库 >

加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载

米飞龙
2023-03-14
问题内容

我正在将React与Firebase一起使用来开发一个小型Web应用程序。为了进行身份验证,我使用了上下文API,并且在上下文中添加了登录用户的详细信息。

AuthProvider.tsx

const AuthProvider: React.FC = props => {
  const [state, setState] = useState<IAuthContext>(authInitialState);
  console.log("Inside AuthProvider");
  useEffect(() => {
    auth.onAuthStateChanged( user => {
      console.log("Auth State changed and user is ----->", user);
      if (user) {
        console.log("User value updated to the context")
        setState({
            ...authInitialState,
          isAuthenticated:!!user,
          permissions:[],
          user:user
        });
      }
      const stateChange = {
        ...authInitialState,
        isAuthenticated: !!user,
        user
      };
      // if (!user) {
        return setState(stateChange);
      // }
    });
  }, []);
  console.log("Rendering AuthProvider", state);
  return (
    <AuthContext.Provider value={state}>{props.children}</AuthContext.Provider>
  );
};
export default AuthProvider;

AuthConsumer.tsx

const withAuthContext = (
  Component: React.ComponentClass<any> | React.FunctionComponent<any>
) => {
  console.log("Rendering AuthConsumer for ");
  return (props: any) => (
    <AuthContext.Consumer>
      {context => <Component {...props} context={context} />}
    </AuthContext.Consumer>
  );
};

export default withAuthContext;

PrivateRoute.tsx

interface PrivateRouteProps extends RouteProps {
    // tslint:disable-next-line:no-any
    component: any;
    context: IAuthContext;
}

const PrivateRoute = (props: PrivateRouteProps) => {
    const { component: Component, context: IAuthContext, ...rest } = props;
    console.log("Private route for ", props);
    return (
        <Route
            {...rest}
            render={(routeProps) =>
                props.context.isAuthenticated ? (
                    <Component {...routeProps} />
                ) : (
                    <Redirect
                        to={{
                            pathname: '/login',
                            state: { from: routeProps.location }
                        }}
                    />
                )
            }
        />
    );
};

export default withAuthContext(PrivateRoute);

App.tsx

return (
        <BrowserRouter>
            <div>
                <Switch>
                    <PublicRoute path="/frame" component={Frame} exact isAuthorized={true}/>
                    <Route path="/login" component={NewLogin} exact isAuthorized={true}/>
                    <PrivateRoute path="/nav" component={NavigationBar} exact/>
                    <PrivateRoute path="/dashboard" component={AnalyticsDashBoard} exact/>
                    <PrivateRoute path="/subscription" component={OrderSuccess} exact/>
                    <PrivateRoute path="/onboarding" component={OnBoarding} exact/>
                </Switch>
            </div>
        </BrowserRouter>
    );

用户已经登录,并且会话持久性设置为本地。问题是,当我尝试本地主机/订阅(这是一条私有路由)时,context.isAuthenticated为false,因为尚未触发“
onAuthStateChanged”观察者,因此它进入了登录页面,但是在几毫秒内,触发了authStateChange并设置了上下文,但它没有用,因为privateroute认为用户未登录,因此应用程序已经导航到登录状态。我想了解如何解决此问题的知识。


问题答案:

页面加载后,Firebase将从本地存储中还原用户的凭据,并与服务器一起检查它们是否仍然有效。由于这是对服务器的调用,因此可能要花费一些时间并异步发生。这是正常的原因firebase.auth().currentUsernull,直到onAuthStateChanged火灾。

你的问题是,有多种原因firebase.auth().currentUser可能是null

  1. firebase.auth().currentUser这是null因为客户端刚刚加载,并且仍在与服务器一起检查凭据。
  2. firebase.auth().currentUser这是null因为客户端针对服务器检查了凭据,并且客户端未登录。
  3. firebase.auth().currentUsernull因为用户从未登录过,所以没有要检查的凭据。

您要在情况2和3而不是情况1下导航。

典型的解决方案是在第一次onAuthStateChanged触发之前不处理导航。届时,您可以确定已针对服务器检查了凭据,或者没有要检查的凭据,在这两种情况下,您都需要导航至登录页面。

加快速度的另一种方法是,当用户首次登录时,自己将一个小令牌存储在本地存储中,然后在应用加载时读取该令牌。如果存在令牌,则可以区分情况1和情况3,并用它稍早导航到正确的页面。

有关此示例,请参见有关架构移动Web应用程序的 I / O讨论。



 类似资料:
  • 问题内容: 我希望在发出ajax调用以更新数据库之前完全加载页面。我可以在body onload事件中调用javascript函数,以使页面完全加载,但是我不确定如何从那里触发Ajax调用。是否有更好的方法来实现此目的(页面加载后,Upadating数据库)? 问题答案: 使用JavaScript库确实很容易,例如使用jQuery,您可以编写: 如果没有jQuery,最简单的版本可能如下所示,但它

  • 我想在加载aboutme时调用servlet GetUserData。jsp页面。 基本上,它所做的是设置一个会话变量,允许用户查看其配置文件信息。 它设置了一个会话变量,因此它不需要调用任何东西,只需在页面加载时继续使用servlet。 这个servlet调用另一种方法来生成SQL语句并准备要发送的数据。 最后,在JSP页面上,我想使用先前声明的会话变量将所有信息(如登录名、密码等)打印到表中。

  • 问题内容: 这有点难以解释,所以我会尽力而为 因此,在加载HTML页面时,我希望有一个很酷的加载屏幕在显示。完成加载后,我希望清除加载屏幕并显示HTML文档。 基本上,我想要这样: CSS: HTML: 页面加载时发生的情况。当页面加载时,将被清除,并显示HTML文档的其余部分。(我正在建立一个学分系统,虽然学分加载时我真的很需要它来说它正在加载,但是人们抱怨他们无法单击任何东西,我不得不告诉他们

  • 问题内容: 我有一个PHP include,它需要一段时间才能加载,因为PHP必须获取很多数据。我不想放慢整个网页的加载,以等待包含此内容,那么如何使用ajax加载该包含内容呢?我不希望通过单击按钮来触发Ajax,而只是希望它在页面加载时加载包含,因此,如果您查看下面的示例,则会在显示内含代码的同时显示“更多HTML内容”。 php仍在加载中。 问题答案: 如果您使用的是jQuery,则可以使用他

  • 好的,首先,我将告诉这应该如何工作:我有一个页面的图片链接下侧,点击一个图片,该链接的信息出现在另一个div。我使用jQuery/Ajax将链接id发布到一个php文件中,并将该数据返回到所选的div。链接应该分页,以便一次显示4个。 这是正在发生的事情:post部分是ok的,当我单击一个链接时,正确的数据将显示在所选的div中。我不知道如何使链接div分页虽然。我需要他们分页时,页面加载,现在当

  • 问题内容: 传统上,要在页面加载后调用JavaScript函数,您需要在包含一些JavaScript的正文中添加一个属性(通常只调用一个函数) 页面加载后,我想运行一些JavaScript代码以使用服务器中的数据动态填充页面的某些部分。因为我使用的是JSP片段,所以我无法使用该属性,而JSP片段没有可以添加属性的元素。 还有其他方法可以在加载时调用JavaScript函数吗?我宁愿不使用jQuer