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

React Native Firebase认证:AuthProvider状态变更未触发App的useEffect

问题:React Native中AuthProvider状态更新无法触发App组件的useEffect

我正在为应用创建注册页面,编写了useAuth Hook及AuthProvider用于处理登录/注册/登出功能,管理isAuthenticated状态与用户信息。注册新用户时,AuthProvider内的effect能正常触发并获取到正确的Firebase用户信息,但App.tsx中监听isAuthenticated的useEffect却未触发,无法根据认证状态切换路由。

相关代码

AuthProvider与useAuth实现

interface authProperties {
  user: {user: any};
  isAuthenticated: boolean;
  register: (
    email: string,
    password: string,
    firstname: string,
    lastname: string,
  ) => Promise<any>;
  login: (email: string, password: string) => Promise<any>;
  logout: () => Promise<any>;
}

export const authContext = createContext<authProperties>({} as authProperties);

export const AuthProvider = ({children}: any) => {
  const [user, setUser] = useState<{user: any}>({user: null});
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, user => {
      console.log('AuthProvider effect triggered', user);
      if (user) {
        setIsAuthenticated(true);
        setUser({user});
      } else {
        setIsAuthenticated(false);
        setUser({user: null});
      }
    });

    return unsubscribe;
  }, []);

const login = async (email: string, password: string) => {
    // login logic
  };
  const register = async (
    email: string,
    password: string,
    firstname: string,
    lastname: string,
  ) => {
    // register logic
  };

  const logout = async () => {
    // logout logic
  };

  const value = {
    user,
    isAuthenticated,
    register,
    login,
    logout,
  };

  return <authContext.Provider value={value}>{children}</authContext.Provider>;
};

export const useAuth = () => {
  const value = useContext(authContext);

  if (!value) {
    throw new Error('useAuth must be used within an AuthProvider');
  }

  return value;
};

App.tsx实现

const App = () => {
  // new auth state
  const {isAuthenticated} = useAuth();

  useEffect(() => {
    console.log('App useEffect triggered');
    if (isAuthenticated) {
      console.log('User is authenticated');
    } else {
      console.log('User is not authenticated');
    }
  }, [isAuthenticated]);

  return (
    <AuthProvider>
      {isAuthenticated ? (
        <TabNavigator />
      ) : (
        <SafeAreaProvider>
          <NavigationContainer>
            <Routes />
          </NavigationContainer>
        </SafeAreaProvider>
      )}
    </AuthProvider>
  );
};

export default App;

问题原因

核心问题是App组件在AuthProvider的外部调用了useAuth。React Context的作用域是Provider包裹的子组件树,App组件本身不在这个作用域内,所以它获取的isAuthenticated值始终是Context的初始值,不会响应AuthProvider内部的状态更新。

解决方案

重构App组件,让AuthProvider作为根组件包裹整个应用,然后在其内部的子组件中使用useAuth获取状态并处理路由切换。

修改后的App.tsx代码

const AppContent = () => {
  const {isAuthenticated} = useAuth();

  useEffect(() => {
    console.log('AppContent useEffect triggered');
    if (isAuthenticated) {
      console.log('User is authenticated');
    } else {
      console.log('User is not authenticated');
    }
  }, [isAuthenticated]);

  return (
    <>
      {isAuthenticated ? (
        <TabNavigator />
      ) : (
        <SafeAreaProvider>
          <NavigationContainer>
            <Routes />
          </NavigationContainer>
        </SafeAreaProvider>
      )}
    </>
  );
};

const App = () => {
  return (
    <AuthProvider>
      <AppContent />
    </AuthProvider>
  );
};

export default App;

额外优化建议

  • 将路由判断逻辑封装成单独的AuthRoute组件,让代码结构更清晰;
  • 在AuthProvider的登录/注册/登出方法中,补充Firebase的实际调用逻辑(比如createUserWithEmailAndPassword、signInWithEmailAndPassword、signOut),确保状态能正确同步;
  • 给authProperties中的user字段定义更具体的类型,避免使用any,提升代码的类型安全性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:45:57