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

Next.js实现列表项转编辑组件及/edit/[todoId]动态路由方案

实现方案:基于路由判断的局部编辑表单切换

针对你的需求,最直接且易实现的方案是结合usePathname/useParams路由钩子,在Todo列表项中动态切换显示内容,同时配合动态路由保证刷新状态一致。以下是具体步骤:

1. 路由结构规划

保留现有路由的同时,新增动态路由/edit/[todoId]:

  • /app/page.js:Todo列表页面(服务器组件,负责数据获取)
  • /app/add/page.js:新增Todo表单
  • /app/edit/[todoId]/page.js:编辑路由页面(复用列表组件,保证刷新状态)
  • /app/components/TodoItem.jsx:客户端组件,负责单个Todo项的显示/编辑切换

2. 实现客户端Todo项组件

将单个Todo项抽为客户端组件,利用路由钩子判断当前是否处于编辑状态,动态渲染普通内容或编辑表单:

// app/components/TodoItem.jsx
'use client';

import { usePathname, useRouter } from 'next/navigation';
import { useState } from 'react';

export default function TodoItem({ todo }) {
  const pathname = usePathname();
  const router = useRouter();
  const [editTitle, setEditTitle] = useState(todo.title);

  // 判断当前是否在编辑该Todo的路由下
  const isEditing = pathname === `/edit/${todo.id}`;

  // 提交编辑内容
  const handleEditSubmit = (e) => {
    e.preventDefault();
    // 这里替换为你的API更新逻辑
    console.log('更新Todo:', { ...todo, title: editTitle });
    // 提交后返回列表页
    router.push('/');
  };

  return (
    <div className="p-3 border rounded mb-2">
      {isEditing ? (
        // 编辑表单状态
        <form onSubmit={handleEditSubmit} className="flex gap-2">
          <input
            type="text"
            value={editTitle}
            onChange={(e) => setEditTitle(e.target.value)}
            className="flex-1 p-2 border rounded"
            required
          />
          <button type="submit" className="px-4 py-2 bg-blue-500 text-white rounded">保存</button>
          <button
            type="button"
            onClick={() => router.push('/')}
            className="px-4 py-2 bg-gray-500 text-white rounded"
          >取消</button>
        </form>
      ) : (
        // 普通Todo项状态
        <div className="flex justify-between items-center">
          <span className={todo.completed ? 'line-through text-gray-500' : ''}>
            {todo.title}
          </span>
          <button
            onClick={() => router.push(`/edit/${todo.id}`)}
            className="px-3 py-1 bg-yellow-500 text-white rounded"
          >编辑</button>
        </div>
      )}
    </div>
  );
}

3. 改造列表页面(服务器组件)

列表页面作为服务器组件负责获取Todo数据,渲染列表和新增按钮:

// app/page.js
import TodoItem from './components/TodoItem';

// 模拟API获取Todo数据(实际项目替换为真实接口)
async function getTodos() {
  return [
    { id: '1', title: '学习Next.js路由', completed: false },
    { id: '2', title: '完成Todo应用', completed: false },
  ];
}

export default async function Home() {
  const todos = await getTodos();

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">Todo列表</h1>
      <div className="space-y-2">
        {todos.map(todo => (
          <TodoItem key={todo.id} todo={todo} />
        ))}
      </div>
      <div className="mt-4">
        <a href="/add" className="px-4 py-2 bg-green-500 text-white rounded inline-block">新增Todo</a>
      </div>
    </div>
  );
}

4. 实现编辑路由页面

创建/edit/[todoId]路由页面,直接复用列表组件,保证刷新URL时页面状态一致:

// app/edit/[todoId]/page.js
import Home from '../../page';
import { getTodos } from '../../page';

// 复用列表页面,路由判断逻辑由TodoItem组件处理
export default function EditTodoPage() {
  return <Home />;
}

// 可选:生成静态路由参数,支持SSG/ISR优化
export async function generateStaticParams() {
  const todos = await getTodos();
  return todos.map(todo => ({
    todoId: todo.id,
  }));
}

核心逻辑说明

  • 点击Todo项的「编辑」按钮时,通过router.push切换URL到/edit/[todoId],客户端组件TodoItem会通过usePathname检测到路由变化,自动切换为编辑表单状态。
  • 刷新/edit/[todoId]时,Next.js会渲染该路由页面,而该页面复用了列表组件,TodoItem会根据当前路由参数找到对应的Todo项,自动显示编辑表单,保持状态一致。
  • 所有页面元素(除了目标Todo项)保持不变,符合你的需求。

内容的提问来源于stack exchange,提问作者M. Çağlar TUFAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:39:50