Firebase authstate 需要很长时间才能在慢速连接上对用户进行身份验证 - React Native
Firebase authstate takes long to authenticate user on slow connection - React Native
我正在创建一个连接到 firebase 的本机反应应用程序。
但是,当我以较慢的互联网速度启动我的应用程序时,需要一段时间才能加载,并且代码显示这是由于等待 authstate 侦听器在慢速连接上变慢造成的。在飞行模式下,它工作正常。
即使网速较慢,我怎样才能加快应用程序的加载速度?
import { getApps, initializeApp } from 'firebase/app';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc, serverTimestamp } from "firebase/firestore"
import AsyncStorage from '@react-native-async-storage/async-storage';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {*****
};
// Initialize Firebase
if (!getApps().length) {
console.log('initializing firebase');
const app = initializeApp(firebaseConfig);
}
包:
{
"name": "tut3",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@gorhom/bottom-sheet": "^4",
"@react-native-async-storage/async-storage": "^1.17.2",
"@react-native-community/datetimepicker": "4.0.0",
"@react-native-community/google-signin": "^5.0.0",
"@react-native-firebase/app": "^14.7.0",
"@react-native-firebase/auth": "^14.7.0",
"@react-native-google-signin/google-signin": "^7.2.2",
"@react-navigation/bottom-tabs": "^6.2.0",
"@react-navigation/material-bottom-tabs": "^6.1.1",
"@react-navigation/native": "^6.0.8",
"@react-navigation/native-stack": "^6.5.2",
"@react-navigation/stack": "^6.1.1",
"expo": "~44.0.0",
"expo-camera": "^12.1.2",
"expo-fast-image": "^1.1.3",
"expo-file-system": "~13.1.4",
"expo-google-app-auth": "~8.3.0",
"expo-image-picker": "^12.0.2",
"expo-location": "~14.0.1",
"expo-status-bar": "^1.2.0",
"expo-updates": "~0.11.6",
"firebase": "^9.6.10",
"moment": "^2.29.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-action-button": "^2.8.5",
"react-native-dropdown-picker": "^5.3.0",
"react-native-gesture-handler": "~2.1.0",
"react-native-gifted-chat": "^0.16.3",
"react-native-image-crop-picker": "^0.37.3",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-maps": "0.29.4",
"react-native-onboarding-swiper": "^1.2.0",
"react-native-paper": "^4.12.0",
"react-native-reanimated": "~2.3.1",
"react-native-safe-area-context": "^4.2.4",
"react-native-screens": "^3.13.1",
"react-native-skeleton-placeholder": "^5.0.0",
"react-native-stars": "^1.2.2",
"react-native-vector-icons": "^9.1.0",
"react-native-web": "0.17.1",
"reanimated-bottom-sheet": "^1.0.0-alpha.22",
"shorthash": "^0.0.2",
"styled-components": "^5.3.5"
},
"devDependencies": {
"@babel/core": "^7.12.9"
},
"private": true
}
这是我的路线文件夹,用于确定在应用程序初始化完成之前在应用程序上显示的内容:
import React, { useContext, useState, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { auth } from './AuthProvider';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc } from "firebase/firestore"
import { AuthContext } from './AuthProvider';
import AuthStack from './AuthStack';
import AppStack from './AppStack';
import AsyncStorage from '@react-native-async-storage/async-storage';
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const onAuthStateChanges = (user) => {
setUser(user);
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing) return null;
return (
<NavigationContainer>
{user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
export default Routes;
谢谢!
编辑:
在建议的答案之后,这就是我已经实现的似乎对我有用的东西。想法是,如果用户之前登录并退出应用程序而没有注销,则加载应用程序堆栈。
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const [previousUser, setPreviousUser] = useState(null);
const onAuthStateChanges = (user) => {
setUser(user);
AsyncStorage.setItem('user', JSON.stringify(user));
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
AsyncStorage.getItem('user').then((value) => {
if (value) {
setPreviousUser(true)
setUser(JSON.parse(value))
}
else {
setPreviousUser(false)
}
})
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing && user) return (
<NavigationContainer>
<AppStack />
</NavigationContainer>
)
if (initializing && !user) return (
<NavigationContainer>
<AuthStack />
</NavigationContainer>
)
return (
<NavigationContainer>
{!initializing && user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
对 initializeApp
的调用是同步的,不需要调用服务器,因此 运行 应该非常快,而且速度与您的互联网连接无关。
但是 onAuthStateChanged
等待身份验证状态恢复, 需要调用服务器来检查用户的凭据是否仍然有效(例如,他们的帐户没有被禁用)。如果互联网连接速度较慢,这可能需要一些时间。
由于大多数此类调用都会成功,所以一个常见的技巧是假设它们会成功,然后如果事实证明该假设是错误的,则当然会更正。要实现这一点,您需要在用户成功登录后在本地存储中存储一个令牌值,然后使用 that 值来确定您的初始导航,而不是等待 onAuthStateChanged
.
Firebaser Michael Bleigh 在 Architecting Mobile Web Apps 上的 Google I/O 视频中谈到了这一点。
我正在创建一个连接到 firebase 的本机反应应用程序。 但是,当我以较慢的互联网速度启动我的应用程序时,需要一段时间才能加载,并且代码显示这是由于等待 authstate 侦听器在慢速连接上变慢造成的。在飞行模式下,它工作正常。
即使网速较慢,我怎样才能加快应用程序的加载速度?
import { getApps, initializeApp } from 'firebase/app';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc, serverTimestamp } from "firebase/firestore"
import AsyncStorage from '@react-native-async-storage/async-storage';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {*****
};
// Initialize Firebase
if (!getApps().length) {
console.log('initializing firebase');
const app = initializeApp(firebaseConfig);
}
包:
{
"name": "tut3",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@gorhom/bottom-sheet": "^4",
"@react-native-async-storage/async-storage": "^1.17.2",
"@react-native-community/datetimepicker": "4.0.0",
"@react-native-community/google-signin": "^5.0.0",
"@react-native-firebase/app": "^14.7.0",
"@react-native-firebase/auth": "^14.7.0",
"@react-native-google-signin/google-signin": "^7.2.2",
"@react-navigation/bottom-tabs": "^6.2.0",
"@react-navigation/material-bottom-tabs": "^6.1.1",
"@react-navigation/native": "^6.0.8",
"@react-navigation/native-stack": "^6.5.2",
"@react-navigation/stack": "^6.1.1",
"expo": "~44.0.0",
"expo-camera": "^12.1.2",
"expo-fast-image": "^1.1.3",
"expo-file-system": "~13.1.4",
"expo-google-app-auth": "~8.3.0",
"expo-image-picker": "^12.0.2",
"expo-location": "~14.0.1",
"expo-status-bar": "^1.2.0",
"expo-updates": "~0.11.6",
"firebase": "^9.6.10",
"moment": "^2.29.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-action-button": "^2.8.5",
"react-native-dropdown-picker": "^5.3.0",
"react-native-gesture-handler": "~2.1.0",
"react-native-gifted-chat": "^0.16.3",
"react-native-image-crop-picker": "^0.37.3",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-maps": "0.29.4",
"react-native-onboarding-swiper": "^1.2.0",
"react-native-paper": "^4.12.0",
"react-native-reanimated": "~2.3.1",
"react-native-safe-area-context": "^4.2.4",
"react-native-screens": "^3.13.1",
"react-native-skeleton-placeholder": "^5.0.0",
"react-native-stars": "^1.2.2",
"react-native-vector-icons": "^9.1.0",
"react-native-web": "0.17.1",
"reanimated-bottom-sheet": "^1.0.0-alpha.22",
"shorthash": "^0.0.2",
"styled-components": "^5.3.5"
},
"devDependencies": {
"@babel/core": "^7.12.9"
},
"private": true
}
这是我的路线文件夹,用于确定在应用程序初始化完成之前在应用程序上显示的内容:
import React, { useContext, useState, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { auth } from './AuthProvider';
// import 'firebase/compat/auth'
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "firebase/auth";
// import 'firebase//firestore'
import { getFirestore, collection, addDoc, query, where, getDocs, deleteDoc, doc, setDoc } from "firebase/firestore"
import { AuthContext } from './AuthProvider';
import AuthStack from './AuthStack';
import AppStack from './AppStack';
import AsyncStorage from '@react-native-async-storage/async-storage';
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const onAuthStateChanges = (user) => {
setUser(user);
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing) return null;
return (
<NavigationContainer>
{user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
export default Routes;
谢谢!
编辑: 在建议的答案之后,这就是我已经实现的似乎对我有用的东西。想法是,如果用户之前登录并退出应用程序而没有注销,则加载应用程序堆栈。
const Routes = () => {
const { user, setUser } = useContext(AuthContext);
const [initializing, setInitializing] = useState(true);
const [previousUser, setPreviousUser] = useState(null);
const onAuthStateChanges = (user) => {
setUser(user);
AsyncStorage.setItem('user', JSON.stringify(user));
if (initializing) setInitializing(false);
console.log(user)
};
useEffect(() => {
AsyncStorage.getItem('user').then((value) => {
if (value) {
setPreviousUser(true)
setUser(JSON.parse(value))
}
else {
setPreviousUser(false)
}
})
const subscriber = onAuthStateChanged(auth, onAuthStateChanges);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing && user) return (
<NavigationContainer>
<AppStack />
</NavigationContainer>
)
if (initializing && !user) return (
<NavigationContainer>
<AuthStack />
</NavigationContainer>
)
return (
<NavigationContainer>
{!initializing && user ? <AppStack /> : <AuthStack />}
</NavigationContainer>
)
};
对 initializeApp
的调用是同步的,不需要调用服务器,因此 运行 应该非常快,而且速度与您的互联网连接无关。
但是 onAuthStateChanged
等待身份验证状态恢复, 需要调用服务器来检查用户的凭据是否仍然有效(例如,他们的帐户没有被禁用)。如果互联网连接速度较慢,这可能需要一些时间。
由于大多数此类调用都会成功,所以一个常见的技巧是假设它们会成功,然后如果事实证明该假设是错误的,则当然会更正。要实现这一点,您需要在用户成功登录后在本地存储中存储一个令牌值,然后使用 that 值来确定您的初始导航,而不是等待 onAuthStateChanged
.
Firebaser Michael Bleigh 在 Architecting Mobile Web Apps 上的 Google I/O 视频中谈到了这一点。