React笔记应用:如何合并双数组实现组件按添加顺序渲染?
问题解决:React笔记应用的顺序渲染与嵌套结构实现
一、实现按添加顺序统一渲染笔记
当前代码用两个独立状态数组存储不同CreateArea创建的笔记,导致渲染时先展示第一个数组的所有内容,再展示第二个。要实现按添加顺序混合渲染,只需将两个数组合并为一个状态数组:
修改步骤
- 合并状态数组:删除
notes2状态,仅保留一个notes数组存储所有笔记 - 统一添加逻辑:只保留一个
addNote函数,两个CreateArea组件都调用该函数添加笔记 - 修复删除逻辑:用时间戳生成唯一
id替代数组索引作为笔记标识,避免删除时索引混乱 - 统一渲染逻辑:仅遍历一次合并后的
notes数组完成渲染
修改后的App组件代码
import React, { useState } from "react"; import Header from "./Header"; import Footer from "./Footer"; import Note from "./Note"; import CreateArea from "./CreateArea"; function App() { const [notes, setNotes] = useState([]); // 统一添加函数,为每个笔记生成唯一id function addNote(newNote) { setNotes(prevNotes => { return [...prevNotes, { ...newNote, id: Date.now() }]; }); } // 统一删除函数,通过唯一id过滤笔记 function deleteNote(id) { setNotes(prevNotes => { return prevNotes.filter(noteItem => noteItem.id !== id); }); } return ( <div> <Header /> {/* 两个CreateArea共享同一个添加函数 */} <CreateArea onAdd={addNote} /> <CreateArea onAdd={addNote} /> {/* 遍历合并后的数组按顺序渲染 */} {notes.map(noteItem => { return ( <Note key={noteItem.id} id={noteItem.id} title={noteItem.title} content={noteItem.content} onDelete={deleteNote} /> ); })} <Footer /> </div> ); } export default App;
修改后,无论哪个CreateArea创建的笔记,都会按添加顺序追加到数组末尾,渲染时自然按时间顺序展示。
二、实现父项与嵌套子项结构
要让第一个CreateArea创建父项、第二个创建对应父项的子项,需要给父项笔记添加children属性存储子项,并修改渲染逻辑支持递归渲染:
修改步骤
- 区分笔记类型:给笔记标记
parent/child类型,子项需关联对应父项的id - 调整状态结构:父项笔记包含
children数组,用于存储关联的子项 - 拆分添加逻辑:分别实现添加父项和子项的函数,子项添加时需指定父项
id - 递归渲染组件:修改
Note组件,使其能渲染自身的子项
修改后的代码示例
App组件
import React, { useState } from "react"; import Header from "./Header"; import Footer from "./Footer"; import Note from "./Note"; import CreateArea from "./CreateArea"; function App() { const [notes, setNotes] = useState([]); // 添加父项笔记,包含children数组存储子项 function addParentNote(newNote) { setNotes(prevNotes => { return [...prevNotes, { ...newNote, id: Date.now(), type: "parent", children: [] }]; }); } // 添加子项笔记,需传入父项id关联 function addChildNote(parentId, newNote) { setNotes(prevNotes => { return prevNotes.map(note => { if (note.id === parentId) { return { ...note, children: [...note.children, { ...newNote, id: Date.now(), type: "child" }] }; } return note; }); }); } // 删除父项时同步删除其子项 function deleteNote(id) { setNotes(prevNotes => { return prevNotes.filter(note => note.id !== id); }); } // 删除指定父项的子项 function deleteChildNote(parentId, childId) { setNotes(prevNotes => { return prevNotes.map(note => { if (note.id === parentId) { return { ...note, children: note.children.filter(child => child.id !== childId) }; } return note; }); }); } return ( <div> <Header /> {/* 第一个CreateArea用于创建父项 */} <CreateArea onAdd={addParentNote} placeholder="添加父项笔记..." /> {/* 第二个CreateArea用于创建子项,实际可添加父项选择器让用户选择关联对象 */} <CreateArea onAdd={(newNote) => notes.length > 0 && addChildNote(notes[0].id, newNote)} placeholder="添加子项笔记..." /> {/* 渲染所有父项及嵌套子项 */} {notes.map(parentNote => ( <Note key={parentNote.id} note={parentNote} onDelete={deleteNote} onDeleteChild={deleteChildNote} /> ))} <Footer /> </div> ); } export default App;
修改后的Note组件(支持递归渲染子项)
import React from "react"; function Note({ note, onDelete, onDeleteChild }) { return ( <div className="note"> <h1>{note.title}</h1> <p>{note.content}</p> <button onClick={() => onDelete(note.id)}>删除</button> {/* 递归渲染当前父项的所有子项 */} {note.children && note.children.map(child => ( <div className="child-note" key={child.id}> <h3>{child.title}</h3> <p>{child.content}</p> <button onClick={() => onDeleteChild(note.id, child.id)}>删除子项</button> </div> ))} </div> ); } export default Note;
说明
- 父项笔记通过
children数组存储关联的子项,实现嵌套结构 - 实际使用时,第二个
CreateArea可添加下拉选择器,让用户选择要关联的父项(示例中简化为关联第一个父项) Note组件递归渲染子项,实现父项与子项的层级展示效果
内容的提问来源于stack exchange,提问作者Technavvy
相关产品推荐
相关产品推荐

