You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo Supabase无效刷新令牌引发React Native应用白屏崩溃求助

React Native/Expo/Supabase应用白屏问题:无效刷新令牌错误引发崩溃

我用React Native、Expo和Supabase开发办公应用,当前遇到的核心问题是:会话销毁时会触发AuthApiError: Invalid Refresh Token: Refresh Token Not Found错误,错误本身不重要,但触发时应用会直接白屏崩溃,目前还没找到崩溃原因。

复现步骤

  • 在电脑模拟器登录应用后关闭
  • 在手机端登录同一账号
  • 在手机端登出(销毁会话)
  • 等待约2小时
  • 重新打开模拟器中的应用,即可触发错误;反向操作的话,手机端会出现白屏

我尝试过用try/catch捕获错误、检测到无会话时跳转登录页,但都没能阻止应用崩溃,推测是错误未被正确处理导致的崩溃。


初始代码

import { supabase } from "@/lib/supabase";
import { AuthApiError, Session } from "@supabase/supabase-js";
import { router } from "expo-router";
import { PropsWithChildren, createContext, useContext, useEffect, useState } from "react";

type AuthData = {
    session: Session | null;
    profile: any;
    loading: boolean;
    isAdmin: boolean;
};

const AuthContext = createContext<AuthData>({
    session: null,
    profile: null,
    loading: true,
    isAdmin: false,
});

export default function AuthProvider({ children }: PropsWithChildren) {
    const [newSession, setNewSession] = useState<Session | null>(null);
    const [profile, setProfile] = useState<any>(null);
    const [loading, setLoading] = useState(true);


    useEffect(() => {
      supabase.auth.getSession().then(({ data: { session } }) => {
        setNewSession(session);
        if (session) {
          // Fetch profile when a session exists
          supabase
            .from('profiles')
            .select('*')
            .eq('id', session.user.id)
            .single()
            .then(({ data }) => {
              setProfile(data || null);
              setLoading(false);
            })
        } else {
          console.log('No session found');
          setLoading(false);
          router.push('/(auth)/sign-in');
        }
      });
      
        supabase.auth.onAuthStateChange(async (_event, session) => {
          setNewSession(session);

          if (session) {
            // fetch profile
            const { data } = await supabase
              .from('profiles')
              .select('*')
              .eq('id', session.user.id)
              .single();
            setProfile(data || null);
          }
        });
      }, []);

    return <AuthContext.Provider value={{session: newSession, loading, profile, isAdmin: profile?.role === 'ADMIN'}}>{children}</AuthContext.Provider>;
}

export const useAuth = () => useContext(AuthContext);

Edit 1:补充完整代码(原仅提供useEffect部分)


Edit 2:参考建议修改后的代码(操作可能有误)

useEffect(() => {
  // Set up the listener for auth state changes
  const { data: { subscription } } = supabase.auth.onAuthStateChange(
    (event, session) => {
      if (event === 'SIGNED_OUT') {
        // Handle sign out by setting session to null
        setNewSession(null);
        router.push('/(auth)/sign-in');
        setLoading(false);
      } else if (session) {
        // Update the session state if a session is present
        setNewSession(session);
        setLoading(false);
      } else {
        // This handles the case when there is no session (e.g., the user is not logged in)
        setNewSession(null);
        router.push('/(auth)/sign-in');
        setLoading(false);
      }
    }
  );

  // Clean up the subscription on component unmount
  return () => {
    subscription.unsubscribe();
  };
}, [router]);

useEffect(() => {
  if (newSession) {
    console.log('session found');
    const fetchProfile = async () => {
      const { data } = await supabase
        .from('profiles')
        .select('*')
        .eq('id', newSession.user.id)
        .single();
      setProfile(data || null);
    }

    fetchProfile();  // Call the async function
  } else {
    console.log(' No session found');
  }
}, [newSession]);

Edit 3:进一步调整后的代码

export default function AuthProvider({ children }: PropsWithChildren) {
const [newSession, setNewSession] = useState<Session | null>(null);
const [profile, setProfile] = useState<any>(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
  // Set up the listener for auth state changes
  const { data: { subscription } } = supabase.auth.onAuthStateChange(
    (event, session) => {
      if (event === 'SIGNED_OUT') {
        // Handle sign out by setting session to null
        setNewSession(null);
        //router.push('/(auth)/sign-in');
        setLoading(false);
      } else if (session) {
        // Update the session state if a session is present
        setNewSession(session);
        setLoading(false);
        console.log(session);

        // fetch profile
        console.log('session found');
        setTimeout(async () => {
                const { data } = await supabase
                  .from('profiles')
                  .select('*')
                  .eq('id', session.user.id)
                  .single();
                setProfile(data || null);
        }, 0);
      } else {
        // This handles the case when there is no session (e.g., the user is not logged in)
        setNewSession(null);
        //router.push('/(auth)/sign-in');
        setLoading(false);
      }
    }
  );

  // Clean up the subscription on component unmount
  return () => {
    subscription.unsubscribe();
  };
}, []);

return <AuthContext.Provider value={{session: newSession, loading, profile, isAdmin: profile?.role === 'ADMIN'}}>{children}</AuthContext.Provider>; 
}

export const useAuth = () => useContext(AuthContext);

内容的提问来源于stack exchange,提问作者ItsaMeEr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 16:04:54