Next.js 13下拉框选择控制表格显示及报错解决
Next.js 13 下拉框筛选表格解决方案
问题根源
- 你的组件默认是服务器组件,可以用
async/await读取本地JSON文件,但不能使用客户端交互API(比如useState、onChange事件) - 当你给组件加上
'use client'后,fetchJson里的fs模块会报错——因为fs是Node.js服务器端模块,浏览器环境根本没有这个API
解决思路:拆分组件
把数据获取和UI交互拆成两个独立组件:
- 服务器组件:只负责读取本地JSON数据、解析校验,然后把数据传递给客户端组件
- 客户端组件:只处理下拉框选中状态、表格条件渲染,完全在浏览器端运行,不碰任何服务器端API
完整代码实现
1. 修改原服务器组件(DashboardContentSection.tsx)
import { fetchJson } from '@/lib/util/fetchJson'; import { Dashboard, dashboard, ProjectServices } from '@/schema/api'; import DashboardFilteredTable from './DashboardFilteredTable'; export default async function DashboardContentSection({ path }: { path: string }) { // 服务器端读取并解析数据 const dashboardData = await fetchJson<Dashboard>(`/${path}/data.json`); const projectsData = await fetchJson<ProjectServices>(`/deploy.json`); const parsedDashboardData = dashboard.parse(dashboardData).data; // 把数据传给客户端组件 return ( <div> <DashboardFilteredTable projects={projectsData.apps} dashboardData={parsedDashboardData} /> </div> ); }
2. 创建客户端组件(DashboardFilteredTable.tsx)
'use client'; import { useState } from 'react'; // 定义props类型 interface Props { projects: string[]; dashboardData: { cluster: string; project: string; version: Array<{ version: string; percentage: number }>; }[]; } export default function DashboardFilteredTable({ projects, dashboardData }: Props) { // 管理选中的项目状态 const [selectedProject, setSelectedProject] = useState<string>(projects[0] || ''); // 根据选中项目过滤表格数据 const filteredData = selectedProject ? dashboardData.filter(item => item.project === selectedProject) : dashboardData; return ( <> <select className='w-full p-2' value={selectedProject} onChange={(e) => setSelectedProject(e.target.value)} > {projects.map((project, index) => ( <option key={index} value={project}> {project} </option> ))} </select> <table className='w-full text-left'> <thead className='bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400'> <tr> <th scope='col' className='px-6 py-3'>Cluster</th> <th scope='col' className='px-6 py-3'>Project</th> <th scope='col' className='px-6 py-3'>Version</th> <th scope='col' className='px-6 py-3'>Traffic</th> </tr> </thead> <tbody> {filteredData.map((i) => ( <tr className='cursor-pointer border-b bg-white hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-600' key={i.cluster} > <td className='px-6 py-3'>{i.cluster}</td> <td className='px-6 py-3'>{i.project}</td> {i.version[0] && ( <> <td key={i.version[0].version} className='px-6 py-3'>{i.version[0].version}</td> <td className='px-6 py-3'>{i.version[0].percentage}%</td> </> )} </tr> ))} </tbody> </table> </> ); }
关键说明
- 服务器组件保留了
fetchJson调用,因为fs只能在服务器端运行,不会触发报错 - 客户端组件通过
useState管理选中状态,onChange事件正常工作,所有交互逻辑都在浏览器端完成 - 数据通过props从服务器组件传递到客户端组件,符合Next.js 13的组件模型规范
内容的提问来源于stack exchange,提问作者Neron Godfather
相关产品推荐
相关产品推荐

