React Router 6+结合Firebase实时数据库获取数据返回null求助
React Router 6+ 与 Firebase 实时数据库配合获取数据问题解决方案
核心问题分析
Firebase 的 onValue 是基于回调的异步 API,你的 getSingleEvent 函数在回调执行前就返回了初始的 null,导致 React Router 的 loader 拿到的是未完成异步操作的结果。
具体修复步骤
1. 将 getSingleEvent 改造为返回 Promise 的函数
把回调逻辑包裹在 Promise 中,当 Firebase 返回数据时 resolve 结果,发生错误时 reject:
import { ref, onValue } from "firebase/database"; import { db } from "./your-firebase-config"; // 替换为你的Firebase配置路径 function getSingleEvent(eventUUID) { return new Promise((resolve, reject) => { const eventRef = ref(db, `events/${eventUUID}`); onValue(eventRef, (snapshot) => { if (snapshot.exists()) { const eventData = snapshot.val(); console.log(eventData); // 保留原有打印逻辑 resolve(eventData); // 将数据传递给Promise调用者 } else { resolve(null); // 无数据时返回null } }, (error) => { reject(error); // 捕获并传递错误 }); }); }
2. 在 React Router loader 中使用 async/await
修改 loader 为异步函数,等待 getSingleEvent 的 Promise 完成:
// main.js 路由配置 import { createBrowserRouter, RouterProvider } from "react-router-dom"; import EventPage from "./EventPage"; const router = createBrowserRouter([ { path: "/event/:eventUUID", element: <EventPage />, loader: async ({ params }) => { try { return await getSingleEvent(params.eventUUID); } catch (error) { console.error("获取事件数据失败:", error); return null; // 或抛出错误交由ErrorBoundary处理 } }, }, ]);
3. 组件中正常使用 useLoaderData
现在 useLoaderData() 即可拿到正确的异步数据:
// EventPage.jsx import { useLoaderData } from "react-router-dom"; function EventPage() { const eventData = useLoaderData(); if (!eventData) { return <div>事件不存在或加载失败</div>; } return ( <div> <h1>{eventData.title}</h1> <p>{eventData.description}</p> </div> ); }
关于 Suspense 和 Await 的补充说明
若要使用 Await 组件,需让 loader 返回包含 Promise 的对象,再配合 Suspense 包裹:
// loader 配置调整 loader: ({ params }) => { return { event: getSingleEvent(params.eventUUID) }; }
// EventPage 组件调整 import { Await, useLoaderData } from "react-router-dom"; import { Suspense } from "react"; function EventPage() { const data = useLoaderData(); return ( <Suspense fallback={<div>加载中...</div>}> <Await resolve={data.event}> {(eventData) => ( <div> <h1>{eventData.title}</h1> <p>{eventData.description}</p> </div> )} </Await> </Suspense> ); }
注意:无论使用哪种方式,核心前提都是 getSingleEvent 必须返回正确的 Promise,否则 Await 也无法拿到有效数据。
内容的提问来源于stack exchange,提问作者Rachel
相关产品推荐
相关产品推荐

