Next.js+Redux Toolkit中使用key属性编辑子组件时出现异常
为什么给React列表项添加key属性后会导致编辑时note.title和note.body变为undefined?
我在Notes.tsx文件中使用map函数渲染NoteItem组件,编辑功能基于Redux Toolkit、Redux Thunk及后端API实现。当为NoteItem添加key={item._id}属性后,前端编辑时会出现错误,提示note.body和note.title为undefined;移除key属性后功能正常,但无法部署到Vercel。
在线应用复现步骤:
- 注册并登录
- 创建新笔记
- 尝试编辑该笔记
相关代码
Notes.tsx
{notes ? notes.map((item: any) => { return <Noteitem key = {item._id} note={item} />; }) : null}
NoteItem.tsx 编辑逻辑
const handleEditConfirm = async (e: any) => { e.preventDefault(); dispatch(editNote(note)); setShowEditModal(false); }; /* 部分渲染代码省略*/ <Modal.Footer> <Button variant="secondary" onClick={handleEditClose}> Close </Button> <Button disabled={note.title.length < 5 || note.body.length < 5} variant="primary" onClick={handleEditConfirm} > Save </Button> </Modal.Footer>
notesSlice.tsx 编辑功能
export const editNote = createAsyncThunk("editNote", async (note:any) =>{ const response = await axios.put("api/notes/editNote",{id:note._id, title:note.title, body:note.body}); const updatedNote:any = await response.data.note; return {note: updatedNote}; }) .addCase(editNote.fulfilled, (state, action) =>{ const id = action.payload.note._id; const newNotesData = (state.notesData as any)?.map((note : any) => note._id === id ? action.payload : note ); return { ...state, notesData : newNotesData } })
后端API(PUT请求)
import { connect } from "@/dbConfig/connect"; import { verifyJwtToken } from "@/lib/jwt"; import Note from "@/models/noteModel"; import { cookies } from "next/headers"; import { NextRequest, NextResponse } from "next/server"; connect(); export async function PUT(request: NextRequest) { try { const { id,title,body } = await request.json(); const token = cookies().get("token")!.value; if (!token) { return NextResponse.json({ status: 401, success: false, message: "Invalid auth-token", }); } const userData: any = verifyJwtToken(token); const note = await Note.findById(id); if (!note) { return NextResponse.json({ status: 500, success: false, message: "Note does not exist", }); } if (note.user != userData.email) { return NextResponse.json({ status: 500, success: false, message: "Invalid User", }); } const updatedNote = await Note.findByIdAndUpdate(id,{ title, body }); return NextResponse.json({ note:updatedNote, status:200, success:true, message:"Note successfully updated" }) } catch (error) { return NextResponse.json({ success: false, error, error_message: "Was not able to delete the note", }); } }
问题原因及修复方案
核心问题1:Redux状态更新时的结构错误
在editNote.fulfilled的处理逻辑中,你用action.payload替换了匹配到的笔记项,但action.payload的结构是{note: updatedNote},而原数组中的每一项是扁平的note对象。添加key后,React会根据key重新匹配组件并更新props,此时传入NoteItem的note变成了嵌套结构{note: {...}},自然找不到title和body属性,导致报错。
修复:
修改Redux slice中的fulfilled处理,用action.payload.note替换原数组项:
.addCase(editNote.fulfilled, (state, action) =>{ const id = action.payload.note._id; const newNotesData = (state.notesData as any)?.map((note : any) => // 替换为action.payload.note,保持结构一致 note._id === id ? action.payload.note : note ); return { ...state, notesData : newNotesData } })
核心问题2:后端返回更新前的文档
findByIdAndUpdate默认返回更新前的文档,这会导致前端拿到旧数据,即使Redux结构正确,也会出现状态不一致的问题。
修复:
添加{new: true}选项,确保返回更新后的文档:
const updatedNote = await Note.findByIdAndUpdate(id,{ title, body }, {new: true}); // 新增此选项
为什么移除key后功能正常?
移除key时,React会复用组件实例,不会严格根据props更新组件内部状态,相当于“侥幸”保留了正确的note引用,但这违反React列表渲染的最佳实践,且Vercel部署会因为缺少必填的key属性而失败。
内容的提问来源于stack exchange,提问作者coder_newbie
相关产品推荐
相关产品推荐

