等待 onSnapshot 获取数据

wait for onSnapshot fetching data

我目前正在学习 React Native (Expo)。 我想使用 redux 和 react-native-firebase。

当我在我的应用程序启动时订阅 firebase (onSnapshot) 时,它 returns 来自 firebase 的数据。但由于 onSnapchot 没有 return 承诺,我不能将它用于我的应用程序加载组件。 因此,我还需要从firebase中获取数据以防止应用程序闪烁。

结果是在我的应用程序启动时我获取了两次数据。

所以我的问题是: 我如何等待 onSnapshot 从 firebase 加载我的数据?

谢谢

const Manager = (props) => {
    //STATE
    const [init, setInit] = useState(false);

    //HOOKS
    const fetchData = useFetchData();
    useInitFirebaseSubscriptions();

    //FUNCTIONS
    async function onInit() {
        console.log('[MANAGER]: loading app...');
        await Promise.all([fetchData()]);
    }
    function onFinishedInit() {
        console.log('[MANAGER]: ...app loading successfull!');
        setInit(true);
    }

    //RETURN
    if (!init) {
        return <AppLoading startAsync={onInit} onFinish={onFinishedInit} onError={console.warn} />;
    } else {
        return props.children;
    }
};
export default Manager;

//INITIAL FETCH BEFORE RENDERING
export function useFetchData() {
    const dispatch = useDispatch();

    return async function () {
        try {
            await firestore()
                .collection('users')
                .get()
                .then((querySnapshot) => dispatch(actions.fetch(querySnapshot)));
        } catch (err) {
            console.log(err.message);
        }
    };
}
//INIT SUBSCRIPTIONS TO FIREBASE
export function useInitFirebaseSubscriptions() {
    const dispatch = useDispatch();

    useEffect(() => {
        console.log('[CONTROLLER]: subscribed to Firebase');
        const unsubscribe = firestore()
            .collection('users')
            .onSnapshot(
                (querySnapshot) => dispatch(action.fetch(querySnapshot)),
                (error) => console.log(error)
            );
        
        return () => {
            unsubscribe();
            console.log('[CONTROLLER]: unsubscribed from Firebase');
        };
    }, []);
}

[MANAGER]: loading app...
[MANAGER]: subscribed to Firebase
[USER_REDUCER]: fetched data
[USER_REDUCER]: fetched data
[MANAGER]: ...app loading successfull!

我认为您可以通过在 redux 中添加一些“正在加载”状态来实现您的目标,以便在您主动从 firebase 获取数据时使用。添加特定于此数据的状态和减速器案例 fetching/loading。

示例代码:

export function useInitFirebaseSubscriptions() {
  const dispatch = useDispatch();

  useEffect(() => {
    console.log('[CONTROLLER]: subscribed to Firebase');

    dispatch(action.startFetch()); // <-- dispatch starting data fetch

    const unsubscribe = firestore()
      .collection('users')
      .onSnapshot(
        (querySnapshot) => {
          dispatch(action.fetch(querySnapshot));
          dispatch(action.completedFetch()); // <-- done fetching
        },
        (error) => {
          console.log(error);
          dispatch(action.completedFetch()); // <-- done fetching
        },
      );
        
    return () => {
      unsubscribe();
      console.log('[CONTROLLER]: unsubscribed from Firebase');
    };
  }, []);
};

Select 来自 redux 存储的加载状态并有条件地渲染加载 UI,否则渲染传递的子项。

const Manager = (props) => {
  const isFetchingData = useSelector(state => state.isFetchingData);

  if (isFetchingData) {
    return <AppLoadingIndicator />;
  }
  return props.children; // *
};

* 通常,您可以在此处使用一些额外的条件渲染,具体取决于数据是否实际上 fetched/returned 并且只是空的,或者是否存在错误等。 .. 基本上提供了一些结果状态。