使用useSWR出现Cannot convert undefined or null to object错误排查
问题
在Next.js中使用useSWR,API路由通过异步查询数据库获取数据。前端代码如下:
const fetcher = (url: string) => axios.get(url).then((r) => r.data); const { data, error } = useSWR("/api/model?data=" + selectedMatch, fetcher, { refreshInterval: 1000, });
执行console.log(data)和console.log(typeof(data))能正常打印出对象,但添加console.log(Object.keys(data))后,出现Cannot convert undefined or null to object错误,且typeof(data)变为undefined。尝试改用useSWRImmutable但无效。
API路由的数据库查询代码如下:
export const GET = async (req: NextRequest) => { await connectToDB(); const matchString: String = req.nextUrl.searchParams.get("data"); const events: any = {}; const promises = matchString.split(",").map(async (match: string) => { try { events[match] = await Events.find({ name: match }).then((res) => res[0]); } catch (error) { events[match] = error; console.log("model/route.js error") } }) await Promise.all(promises) return new Response(JSON.stringify(events), { status: 200 }); };
错误原因
- useSWR异步加载特性导致初始值为空:useSWR是异步获取数据,组件首次渲染时
data为undefined。单独打印data时,浏览器控制台会自动更新显示最终的有效值,但直接调用Object.keys(data)时,初始渲染阶段data仍未undefined,触发类型错误。错误抛出后会干扰后续状态更新,导致typeof(data)也显示为undefined。 - API路由存在空值隐患:
req.nextUrl.searchParams.get("data")可能返回null(比如selectedMatch为空时),此时调用matchString.split(",")会直接报错,API返回的响应不再是预期的对象,进一步导致前端数据异常。 - API错误处理的序列化问题:
catch块中直接将error对象赋值给events[match],而Error对象无法被JSON.stringify正常序列化,可能导致前端接收到的数据不是合法对象。
解决办法
前端侧修复
在访问data的属性或调用Object.keys前,必须先判断data是否存在:
// 方式1:条件判断后执行 if (data) { console.log(Object.keys(data)); } // 方式2:可选链+空值合并简化写法 console.log(data ? Object.keys(data) : []);
API路由侧修复
- 处理
matchString为null的情况,避免调用split时报错; - 修正错误对象的序列化问题,将error替换为可序列化的内容:
export const GET = async (req: NextRequest) => { await connectToDB(); const matchString = req.nextUrl.searchParams.get("data"); const events: any = {}; // 处理matchString为null的情况 if (!matchString) { return new Response(JSON.stringify(events), { status: 200 }); } const promises = matchString.split(",").map(async (match: string) => { try { const res = await Events.find({ name: match }); events[match] = res[0]; } catch (error) { // 用null或错误信息字符串替代Error对象,确保可序列化 events[match] = null; console.log("model/route.js error:", error); } }) await Promise.all(promises); return new Response(JSON.stringify(events), { status: 200 }); };
内容的提问来源于stack exchange,提问作者TungTung
相关产品推荐
相关产品推荐

