React Native && Firebase && useContext - "TypeError: null is not an object (evaluating '_ref.user')" with onAuthStateChanged error

React Native && Firebase && useContext - "TypeError: null is not an object (evaluating '_ref.user')" with onAuthStateChanged error

错误发生在我的 useCachedResources.ts 文件中,但我不确定原因。这是我正在处理的三个文件。我怀疑这与第一次最初为 null 的值有关,但我有条件地呈现我的 Auth 和 App 导航堆栈。另外,模板提供了 useCachedResources,所以也许我应该在其中添加 firebase onAuthStateChanged?

AuthenticatedUserProvider.tsx

import { useState, createContext } from 'react';

export interface IUser {
  uuid: string;
  email: string | null;
}

export type AuthContextType = {
  user: IUser;
  setUser: (newUser: IUser | null) => void;
};

export const AuthenticatedUserContext = createContext<AuthContextType | null>(null);

export const AuthenticatedUserProvider = ({ children }: { children: React.ReactNode }) => {
  const [user, setUser] = useState<IUser | null>(null);

  return (
    <AuthenticatedUserContext.Provider value={user ? { user, setUser } : null}>
      {children}
    </AuthenticatedUserContext.Provider>
  );
};

navigation.ts

export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
  const { user } = useContext(AuthenticatedUserContext) as AuthContextType;

  return (
    <NavigationContainer linking={LinkingConfiguration} theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
      {user ? <AppStack /> : <AuthStack />}
    </NavigationContainer>
  );
}

useCachedResources.ts

export default function useCachedResources() {
  const { user, setUser } = useContext(AuthenticatedUserContext) as AuthContextType;
  const [isLoadingComplete, setLoadingComplete] = useState(false);

  useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        SplashScreen.preventAutoHideAsync();

        await Font.loadAsync({
          ...FontAwesome.font,
          'poppins-400': require('../assets/fonts/poppins-400.ttf'),
          'poppins-700': require('../assets/fonts/poppins-700.ttf'),
          'poppins-900': require('../assets/fonts/poppins-900.ttf'),
        });

        const unsubscribeAuthStateChanged = onAuthStateChanged(auth, (authenticatedUser) => {
          authenticatedUser ? setUser({ uuid: authenticatedUser.uid, email: authenticatedUser.email }) : setUser(null);
        });

        return unsubscribeAuthStateChanged;
      } catch (e) {
        console.warn(e);
      } finally {
        setLoadingComplete(true);
        SplashScreen.hideAsync();
      }
    }

    loadResourcesAndDataAsync();
  }, [user]);

  return isLoadingComplete;
}

因为您使用 null 初始化您的上下文,所以您不能使用解构。比如这个...

const { user } = null;

在浏览器中产生如下错误

Uncaught TypeError: Cannot destructure property 'user' of 'null' as it is null.

我的建议是使用虚拟值初始化您的上下文。这也将使您不必在任何地方使用 as AuthContextType

export type AuthContextType = {
  user: IUser | null; // make user optional instead of the context
  setUser: (newUser: IUser | null) => void;
};

// initialise with a dummy / no-op context
export const AuthenticatedUserContext = createContext<AuthContextType>({
  user: null,
  setUser: () => {}
});

export const AuthenticatedUserProvider: React.FC = ({ children }) => {
  const [user, setUser] = useState<IUser | null>(null);

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