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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 21:42:24