React:从 Firebase Firestore 数据库导出数据的按钮

React: Button to export data from Firebase Firestore database

我正在尝试在我的 React Web 应用程序中制作一个按钮,该按钮将所有数据或最好是特定集合从 Firebase Cloud Firestore 数据库导出为 JSON。

以下是我目前正在处理的内容。这种工作但不正确。当我单击按钮并下载 JSON 时,它将是空的,因为数据尚未加载。当我第二次单击该按钮并再次下载 JSON 时,它将具有所需的数据,因为它是在第一次单击后加载的。在开始下载之前,我尝试了不同的异步和 Promise 结构来等待所有数据,但到目前为止我都失败了。数据总是可以使用 useEffect 预先下载,但这不是一个选项,因为它极大地增加了应用程序的 Firebase 调用。

如何在下载之前正确等待所有数据?有什么不同的方法可以做到这一点吗?

function App() {
    const [download, setDownload] = useState([])
    const downloadLink = useRef()

    const downloadMyCollection = async () => {
        const myCollection = collection(db, 'myCollection')
        const data = await getDocs(myCollection)
        setDownload(data.docs.map((doc) => ({...doc.data(), id: doc.id})))
        downloadLink.current.click()
    }

    return (
        <div>
            <button
                className="downloadButton"
                onClick={ downloadMyCollection }>
                Download Responses
            </button>

            <a
                href={`data:text/json;charset=utf-8,${encodeURIComponent(
                    JSON.stringify(download)
                )}`}
                download='export.json'
                className='hidden'
                ref={downloadLink}>
                isHidden
            </a>
        </div>
    )
}

我不知道 100% 这是否有效,事实是 setState Hook 是异步的,所以即使 setDownload 也会 运行 点击之前,下载状态当 click() 事件 运行.

时将是一个空数组

我的建议是创建一个监听下载状态的 Hooks,检查是否为空,然后触发点击事件。

function App() {
    const [download, setDownload] = useState([])
    const downloadLink = useRef()

    const downloadMyCollection = async () => {
        const myCollection = collection(db, 'myCollection');
        const data = await getDocs(myCollection);
        setDownload(data.docs.map((doc) => ({...doc.data(), id: doc.id})))
    };

    useEffect(() => {
     if(!!download.length) downloadLink.current.click();
    },[download]}

    return (
        <div>
            <button
                className="downloadButton"
                onClick={ downloadMyCollection }>
                Download Responses
            </button>

            <a
                href={`data:text/json;charset=utf-8,${encodeURIComponent(
                    JSON.stringify(download)
                )}`}
                download='export.json'
                className='hidden'
                ref={downloadLink}>
                isHidden
            </a>
        </div>
    )
}