首页 > 解决方案 > 如何使用 Firebase 同时进行分页和接收新消息?

问题描述

我正在使用 Firebase 在 ReactJS 中制作聊天应用程序。

一切正常,但我在尝试使用分页时遇到了一些麻烦

我已经研究过这个并且效果很好:使用 react-firebase-hooks 的分页问题是,一旦我发送/加载一条新消息,它就会重新加载整个数据并复制它。

useList然后之后我尝试使用而不是切换到实时数据库useCollection

使用useList它有点工作,但它用底部元素替换顶部元素,因此删除已加载的信息。所以不是附加列表,它只是调整引用。

我看到另一种方法用于两个单独的列表,一个用于旧消息,一个用于新消息。但这看起来不是最有效的解决方案......

其他问题:[Accepted Answer] 使用两个单独的列表。

聊天.js

const users = [props.uid, auth.currentUser.uid]
users.sort()
const conversationReference = db.collection('conversations').doc(users[0] + "_" + users[1])
const queryFn = React.useCallback(() => {
    let q = conversationReference
        .collection('messages')
        .orderBy('createdAt', 'desc')
        .limit(20)
    return q
}, [props.uid])

const [[messages, queryLoading, error], more] = useFirestoreLoadMore(queryFn)
const sendChat = () => {
        if(message.length > 0) {
            chatReference.add({
                to: props.uid,
                from: auth.currentUser.uid,
                message: message,
                createdAt: new Date(),
            }).then((docRef) => {
                conversationReference.update({
                    lastChat: message,
                    lastActivity: new Date()
                }).then(() => {
                    setMessage('')
                })
            }).catch((error) => {
                console.log("Error sending message")
            })
        }
    }
useEffect(() => {
        if(top && messages[messages.length - 1].data().message)
            more()
    }, [top])

messages[messages.length - 1].data().message: 使用虚拟文档来表示收集结束

使用FirestoreLoadMore.js

import {useCollection, useCollectionData, useCollectionOnce} from 'react-firebase-hooks/firestore'

export const useFirestoreLoadMore = queryFn => {
    const [query, setQuery] = useState(null)
    const [last, setLast] = useState(null)
    const [data, setData] = useState([])

    const [qData, loading, error] = useCollection(query)

    useEffect(() => {
        setData([])
        setQuery(queryFn())
    }, [queryFn])

    useEffect(() => {
        if (qData && qData.query.isEqual(query)) {
            setLast(qData.docs[qData.docs.length - 1])
            //console.log("first: ", data.length, " | second: ", qData.docs.length)
            setData([...data, ...qData.docs])
        }
    }, [qData])

    const more = useCallback(() => {
        setQuery(queryFn().startAfter(last))
    }, [queryFn, setQuery, last])

    return [[data, loading, error], more]
}

问题:我如何分页[messages]ofuseListuseCollection(我对这两种方法都持开放态度。尚未完全确定哪一种最适合)同时还能接收新消息?

标签: reactjsfirebasegoogle-cloud-firestorereact-hooks

解决方案


我决定改变useFirestoreLoadMore

使用FirestoreLoadMore.js

export const useFirestoreLoadMore = queryFn => {
    const baseValue = 20
    const increment = 100
    const [query, setQuery] = useState(null)
    const [limit, setLimit] = useState(baseValue)
    const [data, setData] = useState([])

    const [qData, loading, error] = useCollection(query)

    useEffect(() => {
        setData([])
        setQuery(queryFn().limit(limit))
    }, [queryFn])


    useEffect(() => {
        if (qData && qData.query.isEqual(query)) {
            setData([...qData.docs])
        }
    }, [qData])

    const more = useCallback(() => {
        setQuery(queryFn().limit(limit + increment))
        setLimit(limit + increment)
    }, [queryFn, setQuery])

    return [[data, loading, error], more]
}

这不是我认为的最有效的方式。但是无论如何我都没有看到另一种保持实时更新的方法..


推荐阅读