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

MERN栈中实现动态列表_id去重添加至数组的问题求助

问题描述

我正在基于MongoDB数据构建数组,希望将动态列表中的_id添加到数组中,且_id不会重复。但点击添加数据时,每次只会生成仅含单个元素的新数组,无法实现元素累加。尝试了多种方法,附上相关数据、代码及截图,恳请帮助解决。

数据示例

[
  {
    _id: ObjectId("64d28f3abdc16189260a5521"),
    blood: "A+",
    birth: "2023-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d2edb9d0f86e45a48611b5"),
    blood: "B+",
    birth: "2013-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d2fd40d0f86e45a48611b8"),
    blood: "A+",
    birth: "2023-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d54434a2d26fwdsb83d12ab"),
    blood: "AB+",
    birth: "2013-06-05",
    role: "student",
  },
  {
    _id: ObjectId("64d48526b43hga0b83d12ab"),
    blood: "A+",
    birth: "2023-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d48526bd26fwdsb23sa12ab"),
    blood: "B+",
    birth: "2013-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d48343bd26faa0b83d12ab"),
    blood: "A+",
    birth: "2023-08-05",
    role: "student",
  },
  {
    _id: ObjectId("64d54434a2d26fwdsb83d12ab"),
    blood: "AB+",
    birth: "2013-06-05",
    role: "student",
  },
];

现有代码

import React, { useState } from "react";
import { Col, Container, Row } from "react-bootstrap";
import "./ArrayManipulationComponent.css"; // Import your CSS file

const StudentGrid = ({ student }) => {
  const [elements, setElements] = useState([]);
  const { name, birth, _id } = student;

  const handleButtonClick = (_id) => {
    if (elements.includes(_id)) {
      const updatedElements = elements.filter(id => id !== _id);
      setElements(updatedElements);
    } else {
      setElements([...elements, _id]);
    }
  };

  console.log(elements);


  return (
    <div>
      <Container>
        <Row>
          <Col md={12}>
       
              <div>
              <p>
                <button
                  className={
                    elements.includes(_id) ? "active-button" : "action-button"
                  }
                  onClick={() => handleButtonClick(_id)}
                >
                  Button {_id}
                </button>
              </p>
            </div>
          </Col>
        </Row>
      </Container>
    </div>
  );
};

export default StudentGrid;

问题截图

点击单个按钮后的数组状态
点击另一个按钮后的数组状态


解决方案

问题核心是状态作用域错误:你把elements数组定义在StudentGrid组件内部,而这个组件是每个学生项的独立实例。也就是说,每个学生按钮都维护着自己的elements数组,互相完全独立。点击按钮时只会修改当前组件实例的数组,自然无法实现跨学生的累加。

要解决这个问题,需要将elements状态提升到所有StudentGrid组件的父组件中,让父组件统一管理选中的_id数组,再通过props把状态和更新方法传递给每个StudentGrid实例。

修改后的代码示例

父组件(如StudentList.js)

import React, { useState } from "react";
import StudentGrid from "./StudentGrid";
import { studentsData } from "./your-data-source"; // 导入你的学生数据

const StudentList = () => {
  // 父组件统一管理选中的_id数组
  const [selectedIds, setSelectedIds] = useState([]);

  // 统一的选中/取消选中处理函数
  const toggleStudentSelection = (id) => {
    setSelectedIds(prev => {
      if (prev.includes(id)) {
        return prev.filter(item => item !== id);
      } else {
        return [...prev, id];
      }
    });
  };

  return (
    <div>
      {studentsData.map(student => (
        <StudentGrid
          key={student._id}
          student={student}
          isSelected={selectedIds.includes(student._id)}
          onToggleSelection={() => toggleStudentSelection(student._id)}
        />
      ))}
      {/* 可在这里展示选中的数组 */}
      <p>已选中的ID:{JSON.stringify(selectedIds)}</p>
    </div>
  );
};

export default StudentList;

子组件(StudentGrid.js)

import React from "react";
import { Col, Container, Row } from "react-bootstrap";
import "./ArrayManipulationComponent.css";

const StudentGrid = ({ student, isSelected, onToggleSelection }) => {
  const { birth, _id } = student;

  return (
    <div>
      <Container>
        <Row>
          <Col md={12}>
            <div>
              <p>
                <button
                  className={isSelected ? "active-button" : "action-button"}
                  onClick={onToggleSelection}
                >
                  Button {_id}
                </button>
              </p>
            </div>
          </Col>
        </Row>
      </Container>
    </div>
  );
};

export default StudentGrid;

额外优化建议

  • 由于MongoDB的ObjectId是对象类型,使用includes和filter比较时,建议将_id转为字符串(如_id.toString()),避免因引用不同导致判断错误。
  • 如果选中项较多,使用Set存储_id效率更高(判断存在性的时间复杂度为O(1)),示例如下:
// 父组件中改用Set管理
const [selectedIds, setSelectedIds] = useState(new Set());

const toggleStudentSelection = (id) => {
  setSelectedIds(prev => {
    const newSet = new Set(prev);
    if (newSet.has(id)) {
      newSet.delete(id);
    } else {
      newSet.add(id);
    }
    return newSet;
  });
};

// 判断选中状态时用selectedIds.has(student._id)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:25:35