反应导航身份验证流程。身份验证导航器在主导航器之前短时间可见

时间:2021-03-24 14:56:33

标签: javascript react-native firebase-authentication react-navigation

我使用 firebase 身份验证进行用户身份验证,并使用 react-navigation 根据用户状态呈现不同的导航器。在 Firebase.js 中,我监听 auth 状态变化并相应地设置状态。问题是,当我设置用户数据并隐藏启动画面(npm package react-native-splash-screen)时,在呈现主堆栈之前仍然可以看到身份验证堆栈。我想问一个问题,这个怎么解决?

Firebase.js 上下文提供程序

class Firebase extends React.Component {
    constructor(props: Props) {
        super(props);
        this.state = {
            user: null,
            userDoc: null,
            isLoading: true,
        };
    }
    usersRef = firestore().collection('Users');
    componentDidMount() {
        const { isLoading, user } = this.state;
        auth().onAuthStateChanged(res => {
            if (res) {
                this.usersRef?.doc(res.uid).onSnapshot(async snapshot => {
                    this.setState(
                        {
                            user: res,
                            userDoc: snapshot.exists ? snapshot.data() : null,
                            isLoading:false
                        },
                        () => SplashScreen.hide();
                    );
                });
            } else {
                this.setState(
                    {
                        user: null,
                        isUserSubscribed: false,
                        isLoading: false,
                    },
                    () => SplashScreen.hide();
                );
            }
        });
    }
}

RootNavigator.js

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import MainNavigatorWrapper from '../MainNavigator';
import AuthNavigator from '../AuthNavigator';
import { useFirebase } from '../../context';

const Stack = createNativeStackNavigator();

const RootNavigator = () => {
    const { user } = useFirebase();
    return (
        <NavigationContainer>
            <Stack.Navigator}>
                {!user ? (
                    <Stack.Screen name="Auth" component={AuthNavigator} />
                ) : (
                    <Stack.Screen name="Main" component={MainNavigatorWrapper} />
                )}
            </Stack.Navigator>
        </NavigationContainer>
    );
};

1 个答案:

答案 0 :(得分:1)

我发布此信息是因为我正在寻找解决同一问题的方法。我想出了一个黑客。我确信有更好的方法来解决这个问题,但我还没有弄清楚。这就是我所做的。

在 App.js 中,我返回:

export default function App() {

    const [dataLoaded, setDataLoaded] = useState(false)

    useEffect(() => {
        async function loadApp() {
            try {
                await SplashScreen.preventAutoHideAsync()
                // DO APP LOADING STUFF HERE
            } catch (err) {
                console.warn(err)
            } finally {
                setDataLoaded(true)
            }
        }
        loadApp()
    }, [])

    if (!dataLoaded){
        return null
    }
 
   return (
      <AuthenticationContextProvider>
         <Navigation />
      </AuthenticationContextProvider>
   )
}

如您所见,我使用的是 expo 的 SplashScreen API。因此,诀窍是将所有内容隐藏在启动画面后面,直到身份验证得到解决。

我的导航组件如下所示:

    export const Navigation = () => {
   const { isAuthenticated } = useContext(AuthenticationContext)

    const splashHiddenRef = useRef(false)

    useEffect(() => {
        // splash screen hasn't been hidden yet and authentication has already been determined
        if (!splashHiddenRef.current && isAuthenticated !== null) {
            // delay the splash screen from hiding to quick. Otherwise, the AuthenticationNavigator
            // will flash before the AppNavigator is shown (when user is already authenticated on load)
            setTimeout(() => {
                hideAsync()
            }, 1000)
        }
    }, [isAuthenticated])

   return <NavigationContainer>{isAuthenticated ? <AppNavigator /> : <AccountNavigator />}</NavigationContainer>
}

如您所见,我将启动画面的隐藏延迟了 1 秒。如果网络连接速度较慢,这可能不起作用。我不确定。就目前而言,这是一种我正在搞砸的黑客行为。

我在这次黑客攻击之前的尝试:

它以前不起作用,但在我的上下文中 isAuthenticated 的初始值为 null。当应用加载时,一旦身份验证得到解决,该值将变为真或假(不再为空)。所以,我假设一旦 auth 不为空,那么它应该加载正确的导航器,而不会出现 auth 导航器的闪烁。我相信这与布局的初始渲染有关。 SpashScreen API 像这样解决了这个问题:

Expo SplashScreen

问题是这不是一个很好的例子。据我所知,您不能在导航器中使用 onLayout。我认为您只能在 React.View 的子类中使用它。

也许有人可以提供更好的解决方案......这对我有用......现在