Next.js:客户端新增数据后无需查库更新服务器组件列表
解决并行路由中客户端新增后更新服务器组件列表的方案
核心思路是:保留服务器组件获取初始数据的优势,把列表展示层抽成客户端组件,用Jotai管理全局状态,这样新增后直接用返回的新数据更新状态,无需再次查询数据库,同时避免属性透传。
具体实现步骤
1. 定义Jotai全局状态原子
先创建一个全局状态原子来管理事物列表:
// store/atoms.ts import { atom } from 'jotai'; // 自定义你的事物类型 type Thing = { id: string; name: string; // 其他业务字段 }; export const thingsAtom = atom<Thing[]>([]);
2. 服务器组件负责初始数据获取
服务器组件只做一件事:从数据库拉取初始列表,传递给客户端列表组件:
// app/things/@list/page.tsx (服务器组件) import { query } from '../lib/mysql'; // 你的mysql2查询封装方法 import ThingListClient from './ThingListClient'; export default async function ThingListServer() { // 从数据库获取初始列表数据 const initialThings = await query('SELECT * FROM things'); // 把初始数据传给客户端渲染组件 return <ThingListClient initialThings={initialThings} />; }
3. 客户端列表组件监听状态变化
将列表渲染逻辑放到客户端组件中,初始化Jotai状态并监听更新:
// app/things/@list/ThingListClient.tsx (客户端组件) 'use client'; import { useAtom, useSetAtom } from 'jotai'; import { useEffect } from 'react'; import { thingsAtom } from '@/store/atoms'; interface Props { initialThings: Thing[]; } export default function ThingListClient({ initialThings }: Props) { const [things] = useAtom(thingsAtom); const setThings = useSetAtom(thingsAtom); // 用服务器返回的初始数据初始化全局状态,仅执行一次 useEffect(() => { if (things.length === 0) { setThings(initialThings); } }, [initialThings, things.length, setThings]); return ( <ul> {things.map(thing => ( <li key={thing.id}>{thing.name}</li> ))} </ul> ); }
4. 新增组件直接更新全局状态
在客户端新增组件中,完成新增请求后,用返回的新数据直接更新Jotai状态:
// app/things/@add/page.tsx (客户端组件) 'use client'; import { useState } from 'react'; import { useSetAtom } from 'jotai'; import { thingsAtom } from '@/store/atoms'; import { query } from '../lib/mysql'; export default function AddThingForm() { const [name, setName] = useState(''); const setThings = useSetAtom(thingsAtom); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!name) return; // 执行新增SQL,获取返回的新事物数据 const newThing = await query( 'INSERT INTO things (name) VALUES (?) RETURNING *', [name] ); // 更新列表状态,把新事物加到列表最前面 setThings(prev => [newThing, ...prev]); setName(''); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="输入新事物名称" /> <button type="submit">添加</button> </form> ); }
方案优势
- 首屏数据由服务器组件获取,保证页面加载性能和SEO友好性。
- 新增操作完成后直接用返回的数据更新客户端状态,完全无需再次查询数据库。
- Jotai全局状态避免了多层组件的属性透传,任何客户端组件都能直接操作列表数据。
- 服务器组件无需接触客户端状态库,完全符合Next.js的组件模型规范。
内容的提问来源于stack exchange,提问作者Makazau
相关产品推荐
相关产品推荐

