Expo ReactNative Firebase Получите аутентифицированного пользователя и профиль за один раз

# #firebase #react-native #expo

Вопрос:

Я новичок в Экспо и реагирую. На данный момент я разрабатываю мобильное приложение, которое использует авторизацию Firebase и Firestore для аутентификации и профиля пользователя. Погуглив, я нашел решение использовать ContextProvider для аутентификации Firebase. Я попытался настроить код, чтобы одновременно получить профиль.

Это код для AuthenticatedUserProvider.js

 import React, { useState, createContext } from 'react';

export const AuthenticatedUserContext = createContext({});

export const AuthenticatedUserProvider = ({ children }) => {
    const [user, setUser] = useState(null);
    const [profile, setProfile] = useState(null);

    return (
        <AuthenticatedUserContext.Provider value={{ user, setUser, profile, setProfile }}>
            {children}
        </AuthenticatedUserContext.Provider>
    );
};
 

И я прочитал profile об RotNavigator.js этом ниже

 import React, { useContext, useEffect, useState } from 'react';
import { View, ActivityIndicator } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import * as eva from '@eva-design/eva';
import { ApplicationProvider, IconRegistry } from '@ui-kitten/components';
import { EvaIconsPack } from '@ui-kitten/eva-icons';
import { auth, fs } from '../config/firebase';
import { AuthenticatedUserContext } from './AuthenticatedUserProvider';
import AuthStack from './AuthStack';
import HomeStack from './HomeStack';
import { default as theme } from '../orange-theme.json';

export default function RootNavigator() {
    const { user, setUser, profile, setProfile } = useContext(AuthenticatedUserContext);
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        // onAuthStateChanged returns an unsubscribe
        const unsubscribeAuth = auth.onAuthStateChanged(async authenticatedUser => {
            try {
                if (authenticatedUser) {
                    await setUser(authenticatedUser)
                    const response = await fs.collection("members").doc(authenticatedUser.uid).get();

                    if (response.exists) {
                        let data = response.data();
                        // console.log(data);
                        await setProfile(data);
                        // console.log(profile);
                    }
                } else {
                    await setUser(null);
                    await setProfile(null);
                }

                setIsLoading(false);
            } catch (error) {
                console.log(error);
            }
        });

        // unsubscribe auth listener on unmount
        return unsubscribeAuth;
    }, []);

    if (isLoading) {
        return (
            <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                <ActivityIndicator size='large' />
            </View>
        );
    }

    return (
        <>
            <IconRegistry icons={EvaIconsPack} />
            <ApplicationProvider {...eva} theme={{ ...eva.light, ...theme }}>
                <NavigationContainer>
                    {user ? <HomeStack /> : <AuthStack />}
                </NavigationContainer>
            </ApplicationProvider >
        </>
    );
}
 

Код выглядит как рабочий, за исключением того, что, если я войду в систему, иногда я вижу ошибку в профиле = null и не могу прочитать профиль, но затем он обновляется сам по себе и возвращается для правильной работы.

Может ли кто-нибудь подсказать правильный способ отображения профиля из Firestore?

Причина, по которой я делаю это так, заключается в том, что мне нужен эффективный способ отображения профиля, поскольку в HomeStack есть 3 экрана, на которых должны отображаться некоторые части профиля на каждом экране.

Спасибо вам за вашу помощь.

Комментарии:

1. Вам действительно нужен отдельный пользователь аутентификации и профиль? Это происходит потому, что у вас есть два вызова setState, и они не гарантированно срабатывают вместе, поэтому у вас будут некоторые крайние случаи, когда срабатывает один, но не другой, и вы увидите проблемы, подобные тем, которые вы видите. Что вам нужно от записи пользователя auth? Только жидкость? Почему бы не добавить это в профиль и ТОЛЬКО setProfile . Затем, когда пользователь выходит из системы, та же идея — просто setProfile(null) .

2. Спасибо вам за ваши отзывы. Мне не нужен отдельный пользователь. Это правда, что мне нужно только uid то . Я постараюсь это реализовать.

3. @I’Mjoetoo, но я вызываю setUser с помощью wait, разве это не означает, что нужно дождаться завершения setUser, прежде чем вызывать setProfile? и визуализировать после завершения загрузки setProfile?

4. Для обещаний await означает, что строка будет выполнена и завершена, прежде чем перейти к следующей. Но в React useState это не основано на обещаниях. Когда вы setUser и устанавливаете другие состояния, они добавляются в очередь, а затем выполняются позже — в течение микросекунд, но без гарантированного порядка, поэтому вы периодически получаете эти странные состояния. Потому useState что ты await здесь ничего не делаешь.

5. привет @I’Mjoetoo спасибо за отличное объяснение. Я думаю, что исправил свою проблему, изменив эту строку {профиль ? <HomeStack /> : <HomeStack /><AuthStack />} . поэтому вместо того, чтобы полагаться на пользователя, которого нужно настроить, я полагался на профиль. если они вошли в систему, но профиль еще не установлен, им будет предложено снова войти в систему. но пока с помощью этого исправления я могу избавиться от сообщения об ошибке