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
相关产品推荐
相关产品推荐

