【问题标题】:Firebase onauthstatechanged firing inconsistently on page loadFirebase onauthstatechanged 在页面加载时触发不一致
【发布时间】:2022-01-04 01:27:19
【问题描述】:

我目前正在使用 react 17、react-router-dom v6 和 firebase v9 构建一个网络应用程序。

具体来说,在我的 iPhone SE(同时使用 safari 和 chrome)上加载页面时,我有时会卡在加载状态,因为应用无法确定用户是否登录。

在进一步调试后,我意识到如果我以前登录过,加载页面时并不总是触发 onAuthStateChanged。我可以通过手动刷新迫使 onAuthStateChanged 再次触发的浏览器来规避这种行为,这标志着我回到原点。

据我了解,onAuthStateChanged 应在加载页面时至少触发一次,以确定用户是否通过身份验证。

这种行为特别常见,我在登录时手动在 URL 栏中输入 /login 路径..

我已将路由包装在 AuthProvider 中,如 react-router auth example 所示。我还使用警卫来防止用户在通过身份验证时导航到“/login”,而在未通过身份验证时导航到“/”。

任何帮助或建议将不胜感激。

AuthProvider.js

export function AuthProvider({children}) {
  const [currentUser, setCurrentUser] = useState(null);
  const [isInitialized, setisInitialized] = useState(false);

  
  useEffect(() => {
    const unsubscribe = onAuthStateChanged(
      auth,
      (user) => {
        
        setCurrentUser(user);
        setIsInitialized(true);
      },
    );

    return unsubscribe;
  }, []);

  const value = {
    currentUser,
  };

  if (isInitialized === false) {
    return <LoadingScreen />;
  }
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

App.js

function App() {
  return (
    <div style={{backgroundColor: 'black'}}>
      <AuthProvider>
        <Routes>
          <Route
            path="/login"
            element={
              <RequireLoggedOut>
                <Login />
              </RequireLoggedOut>
            }
          />

          <Route
            path="/"
            element={
              <RequireAuth>
                <Dashboard />
              </RequireAuth>
            }
          />
          
          <Route
            path="/phone"
            element={
              <RequireLoggedOut>
                <LoginPhone />
              </RequireLoggedOut>
            }
          />

          <Route
            path="/profile"
            element={
              <RequireAuth>
                <Profile />
              </RequireAuth>
            }
          />
        </Routes>
      </AuthProvider>
    </div>
  );
}

RequireAuth.js

export default function RequireAuth({children}) {
  const {currentUser} = useAuth();
  let location = useLocation();

  if (!currentUser) {
    return <Navigate to="/login" state={{from: location}} />;
  }
  return children;
}

RequireLoggedOut.js

export default function RequireLoggedOut({children}) {
  const {currentUser} = useAuth();
  let location = useLocation();

  if (currentUser) {
    return <Navigate to="/" state={{from: location}} />;
  }
  return children;
}

更新 1 2021-11-26

我按照 Noah Gwynn 的建议添加了路径名作为依赖项,以及一些日志输出。

useEffect(() => {
    console.log('Mounting AuthContext');
    return () => {
      console.log('Cleaning authcontext');
    };
  }, []);

useEffect(() => {
    console.log('AuthContext path: ' + pathname);
    console.log('Attaching onAuthStateChanged');
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      console.log('auth state changed');
      setCurrentUser(user);
      setisInitialized(true);
    });

    return () => {
      console.log('Detaching onAuth..');
      unsubscribe();
    };
  }, [pathname]);

在尝试通过在 URL 栏中手动输入来加载 /login 路径时,大约 20% 的时间会得到此输出。

LOG: Mounting AuthContext
LOG: AuthContext path: /login
LOG: Attaching onAuthStateChanged

这个输出,在其余时间正确地触发观察者。

LOG: Mounting AuthContext
LOG: AuthContext path: /login
LOG: Attaching onAuthStateChanged
LOG: auth state changed
LOG: Detaching onAuth..
LOG: AuthContext path: /
LOG: Attaching onAuthStateChanged
LOG: auth state changed

更新 2 2021-11-26

此外,如果我将 iPhone 连接到 MacOS 上的 Safari 调试工具,问题就会消失,并且每次都会正确调用 onAuthStateChanged。一旦我禁用调试,行为就会返回,并且除非我刷新页面,否则并不总是调用 onAuthStateChanged..

【问题讨论】:

  • 我知道最近 Safari 出现了一些问题,例如 this one。您使用的是哪个版本的 Firebase Auth SDK?
  • 我目前正在运行 Firebase 9.5.0。但是,我在 Chrome 上也遇到了这个问题。

标签: javascript reactjs firebase firebase-authentication react-router-dom


【解决方案1】:

如果您想确保每次页面更改时都会调用 useEffect,那么您可以获取路径值并将其作为依赖项传递给 useEffect。

获取当前路径:

let pathname = useLocation().pathname

将路径名放入你的 useEffect 依赖数组中:

 useEffect(() => {
    const unsubscribe = onAuthStateChanged(
      auth,
      (user) => {
        
        setCurrentUser(user);
        setIsInitialized(true);
      },
    );

    return unsubscribe;
  }, [pathname]);

【讨论】:

  • 感谢您的建议。我尝试了您的解决方案,但仍然无法持续触发。我添加了一些控制台日志,以了解更改将如何影响事情。我已经用 console.log 添加和控制台输出更新了我的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 2021-12-06
  • 2020-08-28
  • 2011-09-21
  • 2013-12-02
相关资源
最近更新 更多