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

Next.js 14 App Router排序+无限滚动的规范实现方案问询

解决方案

核心问题是useFormState的初始状态仅在组件首次挂载时生效,后续URL参数变化导致initialData更新时,不会自动重置内部状态。我们可以通过在客户端组件中监听查询参数变化,手动同步状态来解决。

步骤1:修改客户端组件,添加状态同步逻辑

在ClientComponent.jsx中,使用useSearchParams获取当前URL的排序参数,结合useEffect监听initialData的变化,当排序方式变更时,手动重置本地状态:

"use client"

import { useState, useEffect, useTransition } from 'react';
import Link from 'next/link';

export default function ClientComponent({ initialData, fetchNextPage }) {
  // 用本地状态管理数据,替代直接依赖useFormState的返回值
  const [dataState, setDataState] = useState(initialData);
  const [isPending, startTransition] = useTransition();

  // 监听initialData变化(URL参数变更时由Server Component传递)
  useEffect(() => {
    // 当排序方向变化时,重置本地状态为新的initialData
    if (initialData.meta.sortDir !== dataState.meta.sortDir) {
      setDataState(initialData);
    }
  }, [initialData, dataState.meta.sortDir]);

  // 加载更多逻辑:调用Server Action并更新状态
  const handleLoadMore = () => {
    startTransition(async () => {
      const newState = await fetchNextPage(dataState);
      setDataState(newState);
    });
  };

  const { data, meta } = dataState;

  return (
    <div>
      <Link href={{ query: { sortDir: meta.sortDir === 'asc' ? 'desc' : 'asc' } }}>
        Sort {meta.sortDir === 'asc' ? 'desc' : 'asc'}
      </Link>

      {/* 数据展示区域 */}
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.content}</li>
        ))}
      </ul>

      {meta.hasNextPage && (
        <button onClick={handleLoadMore} disabled={isPending}>
          {isPending ? 'Loading...' : 'Load more'}
        </button>
      )}
    </div>
  );
}

步骤2:保留Server Component和Server Action逻辑

page.jsx的代码无需修改,它已经能根据URL查询参数正确获取初始数据并传递给客户端组件:

async function fetchNextPage(currentState) {
  "use server"

  const { data, meta } = currentState;

  const response = await fetch(
    `/api/data?offset=${meta.offset + meta.limit}&sortDir=${meta.sortDir}`
  ).then(res => res.json());

  return {
    data: [...data, ...response.data],
    meta: response.meta,
  };
}

export default async function ServerComponent({ searchParams }) {
  const initialData = await fetch(
    `/api/data?offset=0&sortDir=${searchParams.sortDir ?? "asc"}`
  ).then(res => res.json());

  return <ClientComponent initialData={initialData} fetchNextPage={fetchNextPage} />;
}

方案说明

  • 状态同步:通过useEffect监听initialData的排序方向变化,一旦URL参数切换了排序方式,就将本地状态重置为Server Component传递的新初始数据,确保显示内容与当前URL匹配。
  • 加载状态管理:使用useTransition处理加载更多的异步操作,避免UI阻塞,并显示加载状态。
  • Server Actions规范:保留了Server Action处理分页数据的逻辑,符合Next.js 14的Server Components + Server Actions架构要求。

内容的提问来源于stack exchange,提问作者Moses

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:58:22