哪个反应钩子与firestore onsnapshot一起使用?

Posted

技术标签:

【中文标题】哪个反应钩子与firestore onsnapshot一起使用?【英文标题】:Which react hook to use with firestore onsnapshot? 【发布时间】:2020-05-13 15:02:44 【问题描述】:

我在我的 react native 应用程序中使用了很多 firestore 快照。我也在使用 React 钩子。代码如下所示:

useEffect(() => 
    someFirestoreAPICall().onSnapshot(snapshot => 

        // When the component initially loads, add all the loaded data to state.
        // When data changes on firestore, we receive that update here in this
        // callback and then update the UI based on current state

    );;
, []);

起初我认为useState 是存储和更新 UI 的最佳钩子。但是,根据我的useEffect 钩子设置为空依赖数组的方式,当快照回调被更新的数据触发并且我尝试使用新的更改来修改当前状态时,当前状态是未定义的。我相信这是因为关闭。我可以使用useRefforceUpdate() 来解决它,如下所示:

const dataRef = useRef(initialData);

const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState(), []);

useEffect(() => 
    someFirestoreAPICall().onSnapshot(snapshot => 

       // if snapshot data is added
       dataRef.current.push(newData)
       forceUpdate()

       // if snapshot data is updated
       dataRef.current.find(e => some condition) = updatedData
       forceUpdate()

    );;
, []);

return(
// JSX that uses dataRef.current directly
)

我的问题是我是否以不同的方式使用useRefforceUpdate 而不是useState 来正确执行此操作?我必须更新 useRef 钩子并在我的应用程序中调用 forceUpdate() 似乎不正确。在尝试useState 时,我尝试将状态变量添加到依赖数组中,但最终出现了无限循环。我只希望快照函数初始化一次,并且组件中的有状态数据随着后端的变化(在 onSnapshot 回调中触发)随着时间的推移而更新。

【问题讨论】:

【参考方案1】:

如果结合使用useEffect和useState会更好。 UseEffect 将设置和分离监听器,useState 可以只负责你需要的数据。

const [data, setData] = useState([]);

useEffect(() =>  
       const unsubscribe = someFirestoreAPICall().onSnapshot(snap => 
         const data = snap.docs.map(doc => doc.data())
         this.setData(data)
       );

       //remember to unsubscribe from your realtime listener on unmount or you will create a memory leak
       return () => unsubscribe()
, []);

然后你可以在你的应用中从 useState 钩子中引用“数据”。

【讨论】:

所以因为这是一个功能组件,所以我不使用“this”关键字。此外,问题在于setData 没有按照它在快照侦听器内部的方式工作。当我在侦听器中使用setData 时,数据会在组件的下一次渲染中丢失。所以在初始加载之后,下一次后端发生变化并且监听器触发时,我想查看并修改当前的data,但即使我在初始加载时设置它也是未定义的。我可以访问数据的唯一方法是如果我使用 useRef 在渲染之间保存 data 我认为问题在于 onSnapshot 监听器本身带有反应钩子。如果我在带有, [] 的useEffect 中设置状态,但不在onSnapshot 中,事情似乎工作正常。 为什么需要使用“this”关键字?如果您不希望数据更改,请不要使用实时侦听器,您可以使用简单的 get() 调用。【参考方案2】:

我发现在 onSnapshot() 方法内部我无法访问状态(例如,如果我 console.log(state) 我会得到一个空值。

创建一个辅助函数有用,但我不确定这是否是 hack-y 解决方案,但类似于:

[state, setState] = useState([])

stateHelperFunction = () => 
//update state here
setState()


firestoreAPICall.onSnapshot(snapshot => 
stateHelperFunction(doc.data())
)

【讨论】:

【参考方案3】:

use 可以通过 set hook 上的回调获取 currentState

const [state, setState] = useState([]);
firestoreAPICall.onSnapshot(snapshot => 
 setState(prevState =>  prevState.push(doc.data()) return prevState; )
)

prevState 将具有当前状态值

【讨论】:

以上是关于哪个反应钩子与firestore onsnapshot一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 React 钩子(useContext、useEffect)与 Apollo 反应钩子(useQuery)结合起来

反应钩子 useCallback 与循环内的参数

是否可以将 react-datepicker 与反应钩子形式一起使用?

使用 TypeScript 反应 Apollo useQuery 钩子

在反应中如何以及在何处获取数据[重复]

无效的挂钩调用。钩子只能在反应函数组件内部使用...... useEffect,redux