登录 Firebase React Native Expo 后无法获取用户数据

Posted

技术标签:

【中文标题】登录 Firebase React Native Expo 后无法获取用户数据【英文标题】:Can't get user data after logging in Firebase React Native Expo 【发布时间】:2021-09-22 02:23:12 【问题描述】:

我正在尝试使用 React Native / Expo 和 Firebase 创建一个社交媒体应用程序,并且我已经成功地能够创建帐户和登录,但我仍在尝试弄清楚如何获取用户数据,例如用户名用户登录。基本上,当我登录或创建帐户时,我希望个人资料页面显示与登录用户关联的用户名和个人资料图片,但我不知道该怎么做。它可能与 AuthStateChanged() 函数或类似的东西有关,但我不确定。

这是我的 App.js 文件:

import 'react-native-gesture-handler';
import React,  useState  from 'react';
import  LogBox, Text, View  from 'react-native';
import AppLoading from 'expo-app-loading';
import * as Font from 'expo-font';
import Feather from '@expo/vector-icons/Feather'
import  useFonts, Nunito_400Regular as NunitoRegular, Nunito_700Bold as NunitoBold  from '@expo-google-fonts/nunito';
import  NavigationContainer, DefaultTheme  from '@react-navigation/native';
import Navigator from './src/navigation/index';

import * as firebase from "firebase";
import "firebase/auth";
// Your web app's Firebase configuration
var firebaseConfig = 
  apiKey: "AIzaSyB1TxcRpLQq0Zqs0f0FvPitIto0tZo_0xM",
  authDomain: "shutter-42e70.firebaseapp.com",
  projectId: "shutter-42e70",
  storageBucket: "shutter-42e70.appspot.com",
  messagingSenderId: "149059508529",
  appId: "1:149059508529:web:0dbc5bbbb75bf022ef7810"
;

if (firebase.apps.length === 0) 
  firebase.initializeApp(firebaseConfig);


// The theme we'll be using for our navigator
const MyTheme = 
  ...DefaultTheme,
  colors: 
    ...DefaultTheme.colors,
    background: '#FAFAFA'
  ,
;

// Loads the Feather icons (https://docs.expo.io/guides/icons/)
function cacheFonts(fonts) 
  return fonts.map(font => Font.loadAsync(font));


export default function App() 

  const [assetsReady, setAssetsReady] = useState(false);

  async function _loadFonts() 
    const iconFontAssets = cacheFonts([Feather.font])
    await Promise.all([...iconFontAssets]);
  

  // Loads the Nunito font (https://docs.expo.io/guides/using-custom-fonts/)
  let [fontsLoaded] = useFonts(
    NunitoRegular, NunitoBold
  );

  // If the fonts or assets are not loaded, we show a default App Loading screen.
  // Otherwise, we return our Photo Sharing App!
  if (!fontsLoaded || !assetsReady) 
    return <AppLoading
              startAsync=_loadFonts
              onFinish=() => setAssetsReady(true)
              onError=console.warn
            />
  
  return (
    <NavigationContainer theme=MyTheme>
      <Navigator />
    </NavigationContainer>
  );

这是我的 Login.js 文件:

import React from 'react';
import  StyleSheet, View, Text, Image, TextInput, TouchableOpacity  from 'react-native';
import theme from '../../assets/themes';
import  Formik  from 'formik';
import  Octicons, Fontisto  from '@expo/vector-icons';
import Separator from './Separator';
import KeyBoardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';

var errorMsg = '...'

const Login = (navigation) => 
    return (
        <KeyBoardAvoidingWrapper>
            <View>
                <View style = styles.StyledContainer>
                    <View style = styles.InnerContainer>
                        <Image style = styles.PageLogo resizeMode = "cover" source = require('./../../assets/images/logo.png') />
                        <Text style = styles.PageTitle>Shutter</Text>
                        <Text style = styles.TagLine>Social Media for Photographers</Text>
                    </View>
                </View>

                <Formik
                    initialValues = email: '', password: ''
                    onSubmit = (values) => 
                        firebase.auth().signInWithEmailAndPassword(values.email, values.password)
                        .then((result) => 
                            navigation.navigate('Feed');
                        )
                        .catch((error) => 
                            alert(error)
                    )
                
                >
                    (handleChange, handleBlur, handleSubmit, values) => (
                        <View style = styles.styledFormArea>
                            <MyTextInput
                                label = " "
                                icon = "mail"
                                placeholder = "email@email.com"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('email')
                                onBlur = handleBlur('email')
                                value = values.email
                                keyboardType = "email-address"
                            />

                            <MyTextInput
                                label = " "
                                icon = "lock"
                                placeholder = "password"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('password')
                                onBlur = handleBlur('password')
                                value = values.password
                                secureTextEntry = true
                            />

                            <Text style = styles.msgBox>errorMsg</Text>

                            <TouchableOpacity onPress = handleSubmit style = styles.loginButton>
                                <Text style = styles.loginButtonText>Login</Text>
                            </TouchableOpacity>

                            <Separator />

                            <TouchableOpacity onPress = handleSubmit style = styles.googleSigninButton>
                                <Fontisto name = "google" color = theme.colors.white size = 25 ></Fontisto>
                                <Text style = styles.googleSigninButtonText>Sign in with Google</Text>
                            </TouchableOpacity>

                            <View style = styles.signupLinkView>
                                <Text style = styles.signupText>Don't have an account? </Text>
                                <TouchableOpacity style = styles.signupLinkButton>
                                    <Text onPress = () => navigation.navigate('Sign Up') style = styles.signupLinkText>Sign up</Text>
                                </TouchableOpacity>
                            </View>
                        </View>
                    )
                </Formik>
            </View>
        </KeyBoardAvoidingWrapper>
    );
;

const MyTextInput = (label, icon, ...props) => 
    return (
        <View>
            <View style = styles.leftIcon>
                <Octicons name = icon size = 30 color = theme.colors.primary />
            </View>
            <Text style = styles.styledTextInput>label</Text>
            <TextInput style = styles.textInput ...props />
        </View>
    )


const styles = StyleSheet.create(
    StyledContainer: 
        flex: 1,
        padding: theme.spacing.m,
        paddingTop: theme.spacing.l,
        backgroundColor: theme.colors.white,
        marginTop: 80,
    ,
    InnerContainer: 
        justifyContent: 'center',
        alignItems: 'center',
    ,
    PageLogo: 
        width: 100,
        height: 100,
    ,
    PageTitle: 
        ...theme.textVariants.h1,
        marginTop: theme.spacing.m,
    ,
    TagLine: 
        ...theme.textVariants.body3,

    ,
    styledFormArea: 
        justifyContent: 'center',
        marginHorizontal: theme.spacing.l,
        borderRadius: theme.borderRadius.m,
        marginTop: 40,
    ,
    leftIcon: 
        position: 'absolute',
        zIndex: 1,
        marginTop: 28,
        marginLeft: 12,
    ,
    styledTextInput: 
        ...theme.textVariants.body3,
    ,
    textInput: 
        backgroundColor: theme.colors.gray,
        paddingVertical: 10,
        paddingLeft: 50,
        paddingRight: theme.spacing.l,
        borderRadius: theme.borderRadius.m,
    ,
    loginButton: 
        backgroundColor: theme.colors.primary,
        alignItems: 'center',
        marginTop: 20,
        paddingVertical: 8,
        borderRadius: theme.borderRadius.m,
    ,
    loginButtonText: 
        ...theme.textVariants.body2,
        color: theme.colors.white,
    ,
    msgBox: 
        ...theme.textVariants.body3,
        alignSelf: 'center',
    ,
    googleSigninButton: 
        backgroundColor: theme.colors.primary,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        marginTop: 16,
        paddingVertical: 8,
        borderRadius: theme.borderRadius.m,
    ,
    googleSigninButtonText: 
        ...theme.textVariants.body2,
        color: theme.colors.white,
        paddingLeft: 25,
    ,
    signupLinkView: 
        justifyContent: 'center',
        flexDirection: 'row',
        alignItems: 'center',
        padding: theme.spacing.sm,
    ,
    signupText: 
        ...theme.textVariants.body3,
    ,
    signupLinkButton: 

    ,
    signupLinkText: 
        ...theme.textVariants.body3,
        opacity: 0.6,
    ,
)

export default Login;

这是我的 Signup.js 文件:

import React from 'react';
import  StyleSheet, View, Text, Image, TextInput, TouchableOpacity  from 'react-native';
import theme from '../../assets/themes';
import  Formik  from 'formik';
import  Octicons  from '@expo/vector-icons';
import Separator from './Separator';
import KeyboardAvoidingWrapper from './KeyboardAvoidingWrapper';
import firebase from 'firebase';

var errorMsg = '...'

const SignUp = (navigation) => 
    return (
        <KeyboardAvoidingWrapper>
            <View>
                
                <View style = styles.StyledContainer>
                    <View style = styles.InnerContainer>
                        <Image style = styles.PageLogo resizeMode = "cover" source = require('./../../assets/images/logo.png') />
                        <Text style = styles.PageTitle>Shutter</Text>
                        <Text style = styles.TagLine>Social Media for Photographers</Text>
                    </View>
                </View>

                <Formik
                initialValues = fullName: '', email: '', username: '', password: '', confirmPassword: ''
                onSubmit = (values) => 
                    firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
                    .then((result) => 
                        firebase.firestore().collection("users")
                            .doc(firebase.auth().currentUser.uid)
                            .set(
                                fullName: values.fullName,
                                displayName: values.email,
                                username: values.username,
                                password: values.password,
                            )
                        if (values.password === values.confirmPassword)
                            navigation.navigate('Signup Options')
                        else
                            errorMsg = 'Passwords do not match'
                    )
                    .catch((error) => 
                        alert(error)
                    )
                
                >
                    (handleChange, handleBlur, handleSubmit, values) => (
                        <View style = styles.styledFormArea>
                            <MyTextInput
                                label = "Name"
                                icon = "person"
                                placeholder = "John Doe"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('fullName')
                                onBlur = handleBlur('fullName')
                                value = values.fullName
                            />

                            <MyTextInput
                                label = "Email"
                                icon = "mail"
                                placeholder = "email@email.com"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('email')
                                onBlur = handleBlur('email')
                                value = values.email
                                keyboardType = "email-address"
                            />


                            <MyTextInput
                                label = "Username"
                                icon = "person"
                                placeholder = "username"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('username')
                                onBlur = handleBlur('username')
                                value = values.username
                            />

                            <MyTextInput
                                label = "Password"
                                icon = "lock"
                                placeholder = "password"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('password')
                                onBlur = handleBlur('password')
                                value = values.password
                                secureTextEntry = true
                            />

                            <MyTextInput
                                label = "Confirm Password"
                                icon = "lock"
                                placeholder = "retype password"
                                placeholderTextColor = theme.colors.black
                                onChangeText = handleChange('confirmPassword')
                                onBlur = handleBlur('confirmPassword')
                                value = values.confirmPassword
                                secureTextEntry = true
                            />

                            <Text style = styles.msgBox>errorMsg</Text>

                            <TouchableOpacity onPress = handleSubmit style = styles.loginButton>
                                <Text style = styles.loginButtonText>Sign Up</Text>
                            </TouchableOpacity>

                            <Separator />

                            <View style = styles.signupLinkView>
                                <Text style = styles.signupText>Already have an account? </Text>
                                <TouchableOpacity style = styles.signupLinkButton>
                                    <Text onPress = () => navigation.navigate('Login') style = styles.signupLinkText>Login</Text>
                                </TouchableOpacity>
                            </View>
                        </View>
                    )
                </Formik>
            </View>
        </KeyboardAvoidingWrapper>
    );
;

const onSignUp = (values) => 
    console.log(values);


const MyTextInput = (label, icon, ...props) => 
    return (
        <View style = styles.inputFieldView>
            <View style = styles.leftIcon>
                <Octicons name = icon size = 30 color = theme.colors.primary />
            </View>
            <Text style = styles.styledTextInput>label</Text>
            <TextInput style = styles.textInput ...props />
        </View>
    )


const styles = StyleSheet.create(
    StyledContainer: 
        flex: 1,
        padding: theme.spacing.m,
        paddingTop: theme.spacing.l,
        backgroundColor: theme.colors.white,
        marginTop: 80,
    ,
    InnerContainer: 
        justifyContent: 'center',
        alignItems: 'center',
    ,
    PageLogo: 
        width: 100,
        height: 100,
    ,
    PageTitle: 
        ...theme.textVariants.h1,
        marginTop: theme.spacing.m,
    ,
    TagLine: 
        ...theme.textVariants.body3,

    ,
    inputFieldView: 
        marginTop: 12,
    ,
    styledFormArea: 
        justifyContent: 'center',
        marginHorizontal: theme.spacing.l,
        borderRadius: theme.borderRadius.m,
        marginTop: 40,
    ,
    leftIcon: 
        position: 'absolute',
        zIndex: 1,
        marginTop: 28,
        marginLeft: 12,
    ,
    styledTextInput: 
        ...theme.textVariants.body3,
    ,
    textInput: 
        backgroundColor: theme.colors.gray,
        paddingVertical: 10,
        paddingLeft: 50,
        paddingRight: theme.spacing.l,
        borderRadius: theme.borderRadius.m,
    ,
    loginButton: 
        backgroundColor: theme.colors.primary,
        alignItems: 'center',
        marginTop: 20,
        paddingVertical: 8,
        borderRadius: theme.borderRadius.m,
    ,
    loginButtonText: 
        ...theme.textVariants.body2,
        color: theme.colors.white,
    ,
    msgBox: 
        ...theme.textVariants.body3,
        alignSelf: 'center',
    ,
    signupLinkView: 
        justifyContent: 'center',
        flexDirection: 'row',
        alignItems: 'center',
        padding: theme.spacing.sm,
    ,
    signupText: 
        ...theme.textVariants.body3,
    ,
    signupLinkButton: 

    ,
    signupLinkText: 
        ...theme.textVariants.body3,
        opacity: 0.6,
    ,
)

export default SignUp;

很抱歉,如果我的代码写得不是很好,也不是很有条理。我找不到很多关于 firebase 身份验证的好教程,所以这是我在看了 5 个不同的 firebase 身份验证教程后想出的,哈哈。任何帮助将不胜感激!

另外,如果你想查看我的整个项目文件,这里是我的 github 存储库的链接:github repo

【问题讨论】:

【参考方案1】:

您应该使用 redux 或 React 挂钩将用户信息保存到全局状态。

https://reactjs.org/docs/hooks-reference.html#usecontext

https://redux.js.org/introduction/getting-started

在signInWithEmailAndPassword()的回调中返回用户资料数据

firebase.auth().signInWithEmailAndPassword(email, password)
.then((userCredential) => 
  // Signed in 
  var user = userCredential.user;
  /*  user: 
      - email
      - uid
      - displayName
      - emailVerified
      - phoneNumber
      - photoURL
      - metadata
      ...
 
  */
)
.catch((error) => 
  // catch error
);

然后在您的组件/屏幕中,您可以调用状态来显示用户的数据。

【讨论】:

您先生是救生员。我会试试这个! 好的,到目前为止,实现工作正常,但我将如何使用钩子使用户变量全局化?对不起,我有点菜鸟 您应该阅读上面的 2 个链接并尝试在 GitHub 上搜索一些示例存储库。这是一个例子https://github.com/9kmmr/react-native-firebase-noob-example

以上是关于登录 Firebase React Native Expo 后无法获取用户数据的主要内容,如果未能解决你的问题,请参考以下文章

登录 Firebase React Native Expo 后无法获取用户数据

React Native - 将登录的 Firebase 用户重定向到 Home 组件

React native firebase - facebook登录未触发onAuthStateChanged侦听器

如何在使用 firebase/auth 和 react-native 验证他/她的电子邮件后立即登录用户而不创建整个登录页面?

尝试登录时反应本机,Firebase网络错误

成功的 Firebase 身份验证后 React Native App 无法导航