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

React中实现多Card组件选中复选框数量统计并在按钮显示的问题

问题:统计复选框选中数量并在按钮中正确显示

现有功能需统计所有选中的复选框数量并展示在按钮中,但当前每个Card组件单独维护checkedState状态,控制台能输出单组件内的选中数,但按钮无法正确展示全局总选中数量。

问题根源

  • 每个Card组件都有独立的checkedState状态,无法跨组件汇总所有复选框的选中状态
  • 按钮被嵌套在Card组件内部,导致每个Card都会渲染一个独立按钮,无法显示全局总选中数

解决方案

将复选框状态提升到父组件统一管理,父组件负责汇总所有选中状态并渲染统一的按钮:

修改后的Card组件

import React from "react";
import "./card.css";
import semImagem from "../../../../../fileContents/imagensVitrineProfissional/no-image.png";

function Card(props) {
  const { dadosProfissionais, checkedState, handleCheckboxChange } = props;
  const { nomeEmpresa, cidade, imagemMarketplace, idProfissional } = dadosProfissionais;

  const imagemArquivo = imagemMarketplace ? imagemMarketplace : semImagem;

  return (
    <div className="card__profissional" key={idProfissional}>
      <div className="card__header">
        <img
          className="card-imagem"
          src={imagemArquivo}
          alt={`${nomeEmpresa}`}
        />
      </div>
      <div className="card__body">
        <h2 className="card__titulo">{nomeEmpresa}</h2>
        <span className="tag">{cidade}</span>
        <div className="checkbox">
          <label className="checkbox-label">
            Orçamento
            <input
              type="checkbox"
              className="checkbox-input"
              name={nomeEmpresa}
              value={nomeEmpresa}
              checked={checkedState[nomeEmpresa] || false}
              onChange={handleCheckboxChange}
            />
            <span className="checkmark"></span>
          </label>
        </div>
      </div>
    </div>
  );
}

export default Card;

修改后的父组件PopupOrcamentoSimultaneo

import React, { useEffect, useState } from "react";
import "./popupOrcamentoSimultaneo.css";
import Card from "./Card";
import api from "../../../../api";

function PopupOrcamentoSimultaneo({ setOpenPopup }) {
  const [profissionais, setProfissionais] = useState([]);
  const [value, setValue] = useState(
    "Olá! Vamos nos casar e gostariamos de mais informações sobre seu serviço."
  );
  const [profissionalID, setProfissionalID] = useState([]);
  // 父组件统一管理所有复选框的选中状态
  const [checkedState, setCheckedState] = useState({});

  useEffect(() => {
    api.get("profissionais/listarTodos/").then(({ data }) => {
      setProfissionais(data);
    });
  }, []);

  let urlParam = window.location.href.split("=");
  let idProfissionalURL = null;

  if (urlParam.length > 1) {
    idProfissionalURL = urlParam[1];
  }

  useEffect(() => {
    if (idProfissionalURL) {
      api.get(`detalhesProfissional/${idProfissionalURL}`).then(({ data }) => {
        setProfissionalID(data);
      });
    }
  }, [idProfissionalURL]);

  // 统一处理复选框变化的回调
  const handleCheckboxChange = (e) => {
    setCheckedState(prev => ({ ...prev, [e.target.name]: e.target.checked }));
  };

  // 计算总选中数量
  const selectedCount = Object.values(checkedState).filter(Boolean).length;

  let testID = profissionalID.idProfissional;
  let cardsProfissionais = profissionais;
  let listaCardsProfissionais = [];
  const found = cardsProfissionais.find((obj) => obj.idProfissional == testID);
  const foundSegmento = found?.segmento;

  for (let i = 0; i < cardsProfissionais.length; i++) {
    if (cardsProfissionais[i].segmento == foundSegmento) {
      listaCardsProfissionais.push(
        <Card 
          key={i} 
          dadosProfissionais={cardsProfissionais[i]}
          checkedState={checkedState}
          handleCheckboxChange={handleCheckboxChange}
        />
      );
      if (listaCardsProfissionais.length == 4) {
        break;
      }
    }
  }

  const changeValue = (e) => {
    setValue(e.target.value);
  };

  return (
    <div className="popup">
      <div className="popup__container">
        <div className="close-container" onClick={() => setOpenPopup(false)}>
          <i className="fa-solid fa-xmark"></i>
        </div>
        <h2 className="popup__titulo">
          Profissionais desse segmento recomendados para você.
        </h2>

        <div className="cards__profissionais">{listaCardsProfissionais}</div>

        {/* 统一的按钮放在父组件中,显示总选中数 */}
        <button type="submit" className="botao-orcamento">
          Solicitar Orçamento ({selectedCount})
        </button>

        <div className="input-box">
          <label htmlFor="input" className="input-label">
            Escreva sua mensagem
          </label>
          <div>
            <input
              type="text"
              id="input"
              className="input-text"
              placeholder="Olá! Vamos nos casar e gostaríamos de mais informações sobre seu serviço."
              value={value}
              onChange={changeValue}
            />
            <i className="fa-solid fa-pencil"></i>
          </div>
        </div>
      </div>
    </div>
  );
}

export default PopupOrcamentoSimultaneo;

关键修改点

  • 父组件新增checkedState状态,统一管理所有复选框的选中状态
  • 父组件定义handleCheckboxChange回调,传递给每个Card组件
  • Card组件移除自身的checkedState,改为使用父组件传入的状态和回调
  • 将按钮从Card组件移到父组件,基于父组件的checkedState计算总选中数量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:01:07