等待 onSnapshot 获取数据
Posted
技术标签:
【中文标题】等待 onSnapshot 获取数据【英文标题】:wait for onSnapshot fetching data 【发布时间】:2021-11-26 21:59:23 【问题描述】:我目前正在学习 React Native (Expo)。 我想使用 redux 和 react-native-firebase。
当我在我的应用启动时订阅 firebase (onSnapshot) 时,它会从 firebase 返回数据。但由于 onSnapchot 不返回承诺,我不能将它用于我的应用程序加载组件。 因此,我还需要从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!
【问题讨论】:
如果useInitFirebaseSubscriptions
钩子也在获取数据,我看不出const fetchData = useFetchData();
钩子的意义和逻辑。这里的用例是什么,你能澄清一下吗?如果我没看错的话,这似乎是一种奇怪的迂回方式来获得“加载”状态。
firebase.get 方法是异步的,所以我可以等待我的 useFetchData() Hook 完成,然后再渲染我的 UI。结果是当用户打开应用程序时,数据已经存在。 useInitFirebaseSubscriptions 不是异步的,所以我等不及要显示我的 UI 直到获取数据。我希望现在清楚
您不能等待数据填充到您的 redux 存储中吗?您无法从 useInitFirebaseSubscriptions
挂钩中分派开始/结束获取操作以指示您何时主动获取数据?
是的,这正是我的问题。如何等待来自 useInitFirebaseSubscriptions 的数据,或者如何知道 useInitFirebaseSubscriptions 是否仍在获取数据?
【参考方案1】:
我认为您可以通过在 redux 中添加一些“加载”状态来实现您的目标,以便您主动从 firebase 获取数据。添加特定于此数据获取/加载的 state 和 reducer case。
示例代码:
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');
;
, []);
;
从redux store中选择加载状态,有条件地渲染加载UI,否则渲染传入的children。
const Manager = (props) =>
const isFetchingData = useSelector(state => state.isFetchingData);
if (isFetchingData)
return <AppLoadingIndicator />;
return props.children; // *
;
* 通常,您可以在此处使用一些额外的条件渲染,具体取决于数据是否实际获取/返回并且只是空的,或者是否存在错误等...基本上提供了一些结果状态。
【讨论】:
伟大而简单的解决方案,谢谢。还没想过使用 onSnapshot 的回调 ? @sexpomicolon 是的,成功/失败回调在某种程度上是 Promise 链的.then
和 .catch
的同义词,并且由于没有等同于 .finally
,因此不幸的是,您需要复制一些“已解决" 两个处理程序中的逻辑。以上是关于等待 onSnapshot 获取数据的主要内容,如果未能解决你的问题,请参考以下文章
Firestore 抛出“onSnapshot() 需要 1 到 4 个参数”
Firebase firestore onSnapshot 在 useEffect 中无法正常工作