Next.js Router Query数据异常:videos字段出现空字符串求助
Next.js中通过Link传递分类数据后videos字段为空字符串数组的问题
问题场景
我在Next.js项目中从Context API获取所有分类数据展示在首页,通过next/link跳转到分类详情页面[category_slug].jsx。跳转代码如下:
categories.map((category) => ( <Link href={{ pathname: `/categories/${category.category_slug}`, query: category }} className="text-sm hover:underline hover:opacity-60" key={category.id} > {category.name} </Link> ))
此前用相同方式实现视频页面时功能正常,但本次跳转后,分类详情页面能正常获取其他字段,唯独videos字段返回["", ""],不符合预期。接收的数据示例:
{ "id": "9", "name": "test2", "category_slug": "test2", "description": "testt2", "videos": [ "", "" ], "image": "", "created": "2022-12-07T02:07:05.838815Z", "updated": "2022-12-07T02:07:05.838840Z" }
分类详情页面代码:
import React from "react"; const CategoryPage = () => { const router = useRouter() const category = router.query; console.log(category) // captilaze first letter and lowercase the rest const capitalize = (s) => { if (typeof s !== "string") return ""; return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); }; return ( <> { /* <CustomHead title={capitalize(category.name)} />*/} <div className="my-10 mx-auto flex min-h-screen px-24 py-10 "> <div className="flex w-full flex-col bg-white p-10"> { /* <h1 className="text-2xl font-bold up capitalize">{category.name}</h1>*/} <div className="mt-10 grid grid-cols-1 place-items-center gap-2 md:grid-cols-3"> </div> </div> </div> </> ); }; export default CategoryPage;
问题原因
Next.js的Link组件在传递query参数时,会对数据进行URL序列化。如果videos字段原本是对象数组或包含复杂结构的数据,序列化过程中会丢失信息,最终变成空字符串数组。而你之前的视频页面可能传递的是简单字符串或结构更简单的对象,所以没有出现该问题。
另外,直接通过query传递完整对象并非最佳实践,不仅有URL长度限制,还可能引发序列化/反序列化异常。
解决方案
方案1:仅传递slug,在详情页重新请求数据(推荐)
放弃直接传递完整分类对象,只通过路径参数传递category_slug,然后在详情页调用后端接口获取完整分类数据:
首页跳转代码修改:
categories.map((category) => ( <Link href={`/categories/${category.category_slug}`} className="text-sm hover:underline hover:opacity-60" key={category.id} > {category.name} </Link> ))
分类详情页[category_slug].jsx修改:
import React, { useEffect, useState } from "react"; import { useRouter } from 'next/router'; const CategoryPage = () => { const router = useRouter(); const [category, setCategory] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // 确保router参数已加载完成 if (router.isReady && router.query.category_slug) { fetch(`/api/categories/${router.query.category_slug}`) .then(res => res.json()) .then(data => { setCategory(data); setLoading(false); }) .catch(err => { console.error('获取分类数据失败:', err); setLoading(false); }); } }, [router.isReady, router.query.category_slug]); if (loading) return <div className="px-24 py-10">加载中...</div>; if (!category) return <div className="px-24 py-10">分类不存在</div>; const capitalize = (s) => { if (typeof s !== "string") return ""; return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); }; return ( <> <div className="my-10 mx-auto flex min-h-screen px-24 py-10"> <div className="flex w-full flex-col bg-white p-10"> <h1 className="text-2xl font-bold up capitalize">{category.name}</h1> <div className="mt-10 grid grid-cols-1 place-items-center gap-2 md:grid-cols-3"> {/* 渲染videos列表 */} {category.videos.length > 0 ? ( category.videos.map((video, idx) => ( <div key={idx} className="p-4 border rounded"> {video} </div> )) ) : ( <p>暂无视频</p> )} </div> </div> </div> </> ); }; export default CategoryPage;
方案2:手动序列化/反序列化数据(不推荐)
如果必须通过query传递完整对象,可以手动将数据序列化为JSON字符串,在详情页再解析:
首页跳转代码修改:
categories.map((category) => ( <Link href={{ pathname: `/categories/${category.category_slug}`, query: { category: JSON.stringify(category) } }} className="text-sm hover:underline hover:opacity-60" key={category.id} > {category.name} </Link> ))
分类详情页解析数据:
import React from "react"; import { useRouter } from 'next/router'; const CategoryPage = () => { const router = useRouter(); // 解析序列化后的分类数据 const category = router.query.category ? JSON.parse(router.query.category) : null; if (!category) return <div>加载中...</div>; const capitalize = (s) => { if (typeof s !== "string") return ""; return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); }; return ( <> <div className="my-10 mx-auto flex min-h-screen px-24 py-10"> <div className="flex w-full flex-col bg-white p-10"> <h1 className="text-2xl font-bold up capitalize">{category.name}</h1> <div className="mt-10 grid grid-cols-1 place-items-center gap-2 md:grid-cols-3"> {category.videos.map((video, idx) => ( <div key={idx}>{video}</div> ))} </div> </div> </div> </> ); }; export default CategoryPage;
注意:该方案存在URL长度限制,若分类数据过大可能导致传递失败,且数据暴露在URL中存在安全风险,因此不推荐使用。
内容的提问来源于stack exchange,提问作者Aliyasir Naç
相关产品推荐
相关产品推荐

