如何无需刷新页面,用Firestore更新数据同步React组件UI?
问题描述
我开发了一款将数据存储在Firestore并在前端展示的Chrome扩展,目前必须刷新页面才能看到新增数据,用户体验不佳。请问如何无需刷新页面即可更新UI以显示最新数据?
目前我已尝试使用useEffect获取数据,在该钩子中调用了从Chrome本地存储缓存中获取Firestore数据的函数。代码如下:
const getFolderData = () => { getDataFromChrome("docId").then((res: any) => { setDocId(res.docId); }); getDataFromChrome("content").then((res: any) => { for (const item of res.content) { setTiersContent((pre: any) => [...pre, item]); } }); }; useEffect(() => { getFolderData(); }, []);
同时遇到了如下错误(使用Chrome扩展API与后台脚本通信时出现):
Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
一、实现无需刷新更新UI
1. 利用Firestore实时监听(首选方案)
Firestore原生支持实时数据监听,无需依赖Chrome本地存储,直接监听目标文档/集合的变更,数据更新时自动触发UI刷新。
示例代码:
import { doc, onSnapshot } from "firebase/firestore"; import { db } from "./firebaseConfig"; // 你的Firestore配置文件 useEffect(() => { // 监听指定文档的实时变化 const unsubscribe = onSnapshot(doc(db, "你的集合名", docId), (snapshot) => { if (snapshot.exists()) { const latestContent = snapshot.data().content; // 直接更新状态触发UI刷新 setTiersContent(latestContent); } }); // 组件卸载时取消监听,避免内存泄漏 return () => unsubscribe(); }, [docId]);
2. 基于Chrome扩展消息通信触发更新
如果必须依赖Chrome本地存储缓存,可在后台脚本更新缓存后主动向前端发送消息,通知前端重新拉取数据。
前端添加消息监听:
useEffect(() => { // 初始加载数据 getFolderData(); // 监听后台发来的数据更新通知 const handleUpdate = (message) => { if (message.type === "DATA_UPDATED") { setTiersContent([]); // 清空旧数据 getFolderData(); // 重新拉取最新数据 } }; chrome.runtime.onMessage.addListener(handleUpdate); // 组件卸载时移除监听 return () => chrome.runtime.onMessage.removeListener(handleUpdate); }, []);
后台脚本更新缓存后发送通知:
// 当后台完成数据更新并写入本地存储后,发送通知 chrome.storage.local.set({ content: 更新后的内容 }, () => { chrome.runtime.sendMessage({ type: "DATA_UPDATED" }); });
3. 优化现有数据获取逻辑
你当前的getFolderData函数会多次调用setTiersContent,导致频繁重渲染,可改为一次性更新:
const getFolderData = async () => { // 并行获取数据提升效率 const [docIdRes, contentRes] = await Promise.all([ getDataFromChrome("docId"), getDataFromChrome("content") ]); setDocId(docIdRes.docId); // 一次性设置所有内容,避免多次重渲染 setTiersContent(contentRes.content); };
二、修复Chrome扩展通信错误
这个错误源于后台消息监听器标记了异步响应,但在发送响应前消息通道已关闭,修复方案如下:
1. 规范异步消息响应写法
后台脚本使用async/await处理异步逻辑,无需手动返回true,Chrome会自动识别Promise类型的响应:
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (message.type === "GET_DATA") { const data = await 你的异步数据获取逻辑(); sendResponse(data); } });
2. 前端增加错误处理
确保前端调用sendMessage时处理异常,避免因通道关闭导致未捕获错误:
const getDataFromChrome = async (key: string) => { try { const response = await chrome.runtime.sendMessage({ type: "GET_DATA", key }); return response; } catch (error) { console.error("数据获取失败:", error); return { [key]: [] }; // 兜底返回空数据,避免UI崩溃 } };
内容的提问来源于stack exchange,提问作者DerickT
相关产品推荐
相关产品推荐

