如何在点击HostingCard后,在ContactFormular组件展示对应卡片信息?
问题分析与解决方案
你的当前代码不可行,存在几个关键问题:父组件传递的 props 不全、重复渲染表单、表单交互逻辑冲突、状态管理分散。以下是具体的修复和实现方案:
核心问题点
- 父组件未传递
post、showContactDialog、setShowContactDialog等必要 props,直接使用会导致报错 - 每个
HostingCard内部都渲染了ContactFormular,会生成3个重复表单,无法精准控制显示选中卡片的信息 input和label的id/for属性不匹配,点击标签无法选中单选框- 按钮外层
div和按钮本身的onClick嵌套,可能引发事件冒泡导致逻辑混乱
实现步骤
1. 调整父组件:统一状态管理
将表单、选中卡片等状态提升到父组件,只渲染一个 ContactFormular,通过状态控制显示/隐藏及传递选中卡片信息。
import { useState } from 'react'; import HostingCard from './HostingCard'; import ContactFormular from './ContactFormular'; const HostingList = () => { // 从WP API获取的套餐数据 const [hostings, setHostings] = useState([]); // 存储选中的套餐信息 const [selectedHosting, setSelectedHosting] = useState(null); // 控制表单显示/隐藏 const [showContactDialog, setShowContactDialog] = useState(false); // 其他全局状态(根据你的业务需求保留) const [pro, setPro] = useState(false); const [ssl, setSsl] = useState(false); // 处理卡片选中逻辑 const handleSelectHosting = (hosting) => { setSelectedHosting(hosting); setShowContactDialog(true); setPro(false); }; // 表单提交逻辑 const handleSubmit = (e) => { e.preventDefault(); // 这里可以使用 selectedHosting 处理提交 console.log('提交的套餐:', selectedHosting); setShowContactDialog(false); }; return ( <div> {/* 渲染套餐卡片 */} {hostings.map((hosting) => ( <HostingCard key={hosting.id} hosting={hosting} onSelect={handleSelectHosting} pro={pro} setPro={setPro} {/* 如果需要post数据,确保父组件有该数据并传递 */} // post={yourPostData} /> ))} {/* 仅渲染一个表单,根据状态显示 */} {showContactDialog && selectedHosting && ( <ContactFormular hosting={selectedHosting} showContact={showContactDialog} setShowContact={setShowContactDialog} handleSubmit={handleSubmit} ssl={ssl} pro={pro} setPro={setPro} // post={yourPostData} /> )} </div> ); }; export default HostingList;
2. 重构 HostingCard 组件:简化逻辑
移除不必要的 props,修复交互问题,将选中逻辑委托给父组件。
const HostingCard = ({ hosting, onSelect, pro, setPro /*, post */ }) => { // 生成唯一的单选框ID,确保和label匹配 const radioId = `hosting-${hosting.id}`; return ( <div className='noselect hosting-options'> <input type="radio" id={radioId} name="startup" /> <div className='card selected-card'> <form> {/* 修复label的for属性与input的id匹配 */} <label htmlFor={radioId} className='label'> <div className='card-header'> <h5>{hosting.acf.title}</h5> <p>{hosting.acf.beskrivelse}</p> </div> <div className='pakke-detaljer'> <div> <p style={{ display: hosting.acf.deltaljer ? 'block' : 'none' }}> {hosting.acf.deltaljer} </p> </div> </div> <div className='button-header'> {/* 设为button类型,避免触发表单默认提交 */} <button type="button" className='btn' onClick={() => { setPro(false); onSelect(hosting); }} > Vælg </button> </div> </label> </form> </div> </div> ); }; export default HostingCard;
3. ContactFormular 组件接收选中数据
在 ContactFormular 中直接使用 props.hosting 即可获取当前选中卡片的信息,比如:
const ContactFormular = ({ hosting, ...restProps }) => { return ( <div className="contact-form"> <h3>请联系我们 - {hosting.acf.title}</h3> <p>套餐描述:{hosting.acf.beskrivelse}</p> {/* 其他表单内容 */} </div> ); }; export default ContactFormular;
关键优化点
- 状态提升:将选中卡片、表单显示状态统一放在父组件管理,符合React单向数据流原则
- 避免重复渲染:只渲染一个表单,通过状态控制显示,提升性能
- 修复交互问题:确保单选框和标签的ID匹配,按钮类型设为button避免默认提交
- 简化组件职责:
HostingCard只负责展示卡片和触发选中事件,表单逻辑交给父组件和ContactFormular处理
内容的提问来源于stack exchange,提问作者Mattyb
相关产品推荐
相关产品推荐

