You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 16:00:59