Firebase onauthstatechanged 在页面加载时触发不一致
Posted
技术标签:
【中文标题】Firebase onauthstatechanged 在页面加载时触发不一致【英文标题】:Firebase onauthstatechanged firing inconsistently on page load 【发布时间】: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 上也遇到了这个问题。 【参考方案1】:如果您想确保每次页面更改时都会调用 useEffect,那么您可以获取路径值并将其作为依赖项传递给 useEffect。
获取当前路径:
let pathname = useLocation().pathname
将路径名放入你的 useEffect 依赖数组中:
useEffect(() =>
const unsubscribe = onAuthStateChanged(
auth,
(user) =>
setCurrentUser(user);
setIsInitialized(true);
,
);
return unsubscribe;
, [pathname]);
【讨论】:
感谢您的建议。我尝试了您的解决方案,但仍然无法持续触发。我添加了一些控制台日志,以了解更改将如何影响事情。我已经用 console.log 添加和控制台输出更新了我的帖子。以上是关于Firebase onauthstatechanged 在页面加载时触发不一致的主要内容,如果未能解决你的问题,请参考以下文章
firebase.auth().onAuthStateChanged 不工作
如何从 firebase.auth().onAuthStateChanged 中提取数据
.onAuthStateChanged 方法是不是计入 Firebase 身份验证验证?
TypeError: firebase.auth(...).onAuthStateChanged 不是函数