admin管理员组

文章数量:1296907

Everything auth-wise is working fine. I even have a loading state setup so that the loader shows until the state is changed, but I still get this flickering on reload. This flickering only happens with Supabase. I was using the Firebase version before and it worked perfectly with my code.

Here is a video for reference: .jpg

Edit: Updated code to current version

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

  useEffect(() => {
    const session = supabase.auth.session();
    setUser(session?.user ?? null);

    const { data: listener } = supabase.auth.onAuthStateChange((_: any, session: any) => {
      setUser(session?.user ?? null);
    });

    setIsLoading(false);
    return () => {
      listener?.unsubscribe();
    };
  }, []);

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

  return (
    <NavigationContainer linking={LinkingConfiguration}>{user ? <AppStack /> : <AuthStack />}</NavigationContainer>
  );
}

Everything auth-wise is working fine. I even have a loading state setup so that the loader shows until the state is changed, but I still get this flickering on reload. This flickering only happens with Supabase. I was using the Firebase version before and it worked perfectly with my code.

Here is a video for reference: https://i.sstatic/rxGDn.jpg

Edit: Updated code to current version

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

  useEffect(() => {
    const session = supabase.auth.session();
    setUser(session?.user ?? null);

    const { data: listener } = supabase.auth.onAuthStateChange((_: any, session: any) => {
      setUser(session?.user ?? null);
    });

    setIsLoading(false);
    return () => {
      listener?.unsubscribe();
    };
  }, []);

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

  return (
    <NavigationContainer linking={LinkingConfiguration}>{user ? <AppStack /> : <AuthStack />}</NavigationContainer>
  );
}
Share Improve this question edited May 27, 2022 at 15:14 asked May 26, 2022 at 1:14 user14263509user14263509
Add a ment  | 

3 Answers 3

Reset to default 5

Ok, Supabase has released some updates since I first asked this question. Here is how I am now able to stop flickering when loading the application.

First, we need to set up our AuthContext for our application. Be sure to wrap your App.tsx with the <AuthContextProvider>.

AuthContext.tsx

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

import { Session, User } from '@supabase/supabase-js';

import { supabase } from '../config/supabase';

export const AuthContext = createContext<{ user: User | null; session: Session | null }>({
  user: null,
  session: null,
});

export const AuthContextProvider = (props: any) => {
  const [userSession, setUserSession] = useState<Session | null>(null);
  const [user, setUser] = useState<User | null>(null);

  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => {
      setUserSession(session);
      setUser(session?.user ?? null);
    });

    const { data: authListener } = supabase.auth.onAuthStateChange(async (event, session) => {
      console.log(`Supabase auth event: ${event}`);
      setUserSession(session);
      setUser(session?.user ?? null);
    });

    return () => {
      authListener.subscription;
    };
  }, []);

  const value = {
    userSession,
    user,
  };
  return <AuthContext.Provider value={value} {...props} />;
};

export const useUser = () => {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useUser must be used within a AuthContextProvider.');
  }
  return context;
};

Now, if you're using React Navigation like me we need to check if we have a valid user to send them to the logged-in home screen. Here's how I do it.

Navigation.tsx

export default function Navigation() {
  const { user } = useUser();

  return (
    <NavigationContainer linking={LinkingConfiguration}>
      {user ? <AppStackNavigator /> : <AuthStackNavigator />}
    </NavigationContainer>
  );
}

To recap for others, onAuthStateChange will not execute on first page load so you are triggering it using the getUserAuthStatus async function. However session() function is not async and will immediately return a result of null if there is no user session, or return a session that has been stored in localStorage.

In this case the result of the getUserAuthStatus will always return null. Then onAuthStateChange will trigger with the SIGNED_IN event and a session which will then set the user.

Furthermore the onAuthStateChange function should be registered before you perform the session step so as to capture any events triggered. In the current form an event may be triggered directly after the session() call but before the handler is registered.

So to recap the rendering steps will be:

Step 1

isLoading: true
user: null

Step 2

isLoading: false
user: null

Step 3

isLoading false
user: {...}

So far as I can tell, using session directly without thinking it's async will do the trick.

React / Next Auth helpers provide decent help these days, so you do not need to write your own useUser or useSession: https://supabase./docs/guides/auth/auth-helpers

本文标签: