React Native useEffect多次调用Firestore监听器

时间:2019-10-20 20:34:13

标签: typescript firebase react-native use-effect

我正在使用React Native(0.61.2)和TypeScript(3.6.4)做一个移动应用程序。我正在使用React Native Firebase集合中的Firebase身份验证和Firebase Firestore。

我正在尝试:

  1. 监听Auth状态更改(使用onAuthStateChanged)
  2. 收听用户身份验证更改(使用onUserChanged)
  3. 收听用户文档(使用onSnapshot)
  4. 收听名为brand的特定文档(使用onSnapshot)

我要在上下文中保存先前侦听器的userAuth,用户文档和品牌文档。

/**
 * Types
 */
type UserAuth = FirebaseAuthTypes.User | null;
type User = UserDoc | null;
type Brand = BrandDoc | null;
type ContextProps = {
  userAuth: UserAuth;
  user: User;
  brand: Brand;
} | null;

/**
 * Context
 */
export const Context = createContext<ContextProps>(null);

function App() {
  const [initializing, setInitializing] = useState(true);

  const [listenUserAuth, setListenUserAuth] = useState(false);
  const [userAuth, setUserAuth] = useState<UserAuth>(null);

  const [listenUser, setListenUser] = useState(false);
  const [user, setUser] = useState<User>(null);

  const [listenBrand, setListenBrand] = useState(false);
  const [brand, setBrand] = useState<Brand>(null);

  /** Listen for auth state changes */
  useEffect(() => {
    const authListener = auth().onAuthStateChanged(result => {
      setUserAuth(result);
      if (initializing && !listenUserAuth) {
        setInitializing(false);
        setListenUserAuth(true);
        setListenUser(true);
        setListenBrand(true);
      }
    });

    return () => {
      if (authListener) {
        console.log('removing auth state listener');
        authListener();
      }
    };
  }, [initializing, listenUserAuth]);

  /** Listen for user auth changes */
  useEffect(() => {
    let userAuthListener: () => void;

    if (listenUserAuth) {
      userAuthListener = auth().onUserChanged(result => {
        setUserAuth(result);
      });
    }

    return () => {
      if (userAuthListener) {
        console.log('removing user auth listener');
        userAuthListener();
      }
    };
  }, [listenUserAuth]);

  /** Listen for user document changes */
  useEffect(() => {
    let userListener: () => void;

    if (listenUser) {
      if (!userAuth) {
        return;
      }

      console.log('listening user document');
      userListener = firestore()
        .collection('users')
        .doc(userAuth.uid)
        .onSnapshot(querySnapshot => {
          console.log('User querySnapshot: ', querySnapshot.data());
          setUser(querySnapshot.data());
        });
    }

    return () => {
      if (userListener) {
        console.log('removing user document listener');
        userListener();
      }
    };
  }, [listenUser, userAuth]);

  /** Listen for brand document changes */
  useEffect(() => {
    let brandListener: () => void;

    if (listenBrand) {
      if (!userAuth) {
        return;
      }

      console.log('listening brand document');
      brandListener = firestore()
        .collection('brands')
        .doc('31uOUtUkVYg8z953UdxS')
        .onSnapshot(querySnapshot => {
          console.log('Brand querySnapshot: ', querySnapshot.data());
          setBrand(querySnapshot.data());
        });
    }

    return () => {
      if (brandListener) {
        console.log('removing brand document listener');
        brandListener();
      }
    };
  }, [listenBrand, userAuth]);

  if (initializing) {
    return (
      <View style={{flex: 1, justifyContent: 'center'}}>
        <ActivityIndicator size="large" color="#000" />
      </View>
    );
  }

  function container(children: ReactNode | ReactNode[]) {
    return <PaperProvider theme={theme}>{children}</PaperProvider>;
  }

  return container(
    userAuth && user && brand ? (
      <Context.Provider value={{userAuth, user, brand}}>
        <SignedInStack />
      </Context.Provider>
    ) : (
      <SignedOutStack />
    )
  );
}

export default App;

在另一个组件中,当用户注销时,所有侦听器都在重新侦听并多次删除自身。

日志:

enter image description here

这将对Firebase添加不必要的读取和写入,这会增加成本。

我是使用 useEffect 的新手,我很确定自己做错了什么。我不完全了解useEffect需要开始监听用户文档和品牌文档一次并删除一次监听器所需的依赖项。在这样做之前,我尝试阅读,我认为我做对了。

  • 出于某些我看不到的原因, ActivityIndi​​cator 也被删除,但没有用户文档和品牌文档。在设置UserAuth,User文档和Brand文档之前,它应该是可见的。

我的目标是:

  1. 显示ActivityIndi​​cator,直到设置了所有侦听器。
  2. 仅听和删除一次侦听器,以避免不必要的读写。

0 个答案:

没有答案