React中如何高效实现多手风琴展示不同内容?
高效实现React多手风琴组件的方案
结论:完全可以将不同手风琴拆分为独立组件(类组件或函数组件),同时通过通用组件复用逻辑,大幅简化代码。
下面提供两种落地方案:
方案一:通用手风琴容器 + 独立内容组件
先封装一个通用的手风琴容器组件,负责处理展开/收起的状态逻辑,将手风琴的标题和内部内容通过props传入。这样每个手风琴的表单内容可以拆成独立组件,复用容器的交互逻辑。
1. 通用手风琴容器(类组件版本)
import React, { Component } from 'react'; class Accordion extends Component { state = { isExpanded: false }; toggleExpand = () => { this.setState(prevState => ({ isExpanded: !prevState.isExpanded })); }; render() { const { title } = this.props; const { isExpanded } = this.state; return ( <div className="accordion-container"> <div className="dropdown-header" onClick={this.toggleExpand}> <h4 className="dropdown-text">{title}</h4> <span className="dropdown-selection">{isExpanded ? '-' : '+'}</span> </div> {isExpanded && <div className="wrapper">{this.props.children}</div>} </div> ); } } export default Accordion;
2. 独立的内容组件(比如配送信息表单)
import React from 'react'; const ShippingInfo = () => { return ( <div className="row"> <div className="col-md-6"> <div className="info-group mb-3"> <label>First name</label> <input type="text" className="info-input" name="firstname" /> </div> </div> <div className="col-md-6"> <div className="info-group mb-3"> <label>Last name</label> <input type="text" className="info-input" name="lastname" /> </div> </div> {/* 其他配送信息表单元素 */} </div> ); }; export default ShippingInfo;
3. 父组件中组合使用
import React from 'react'; import Accordion from './Accordion'; import ShippingInfo from './ShippingInfo'; import ShippingOptions from './ShippingOptions'; // 另一个手风琴内容组件 const CheckoutPage = () => { return ( <div className="checkout-container"> <Accordion title="Shipping Information"> <ShippingInfo /> </Accordion> <Accordion title="Shipping Options"> <ShippingOptions /> </Accordion> </div> ); }; export default CheckoutPage;
方案二:拆分独立的手风琴类组件
如果每个手风琴需要独立的状态管理或独特逻辑(比如配送选项需要处理选择后的联动),可以直接将每个手风琴写成独立的类组件:
示例:配送信息手风琴组件
import React, { Component } from 'react'; class ShippingInfoAccordion extends Component { state = { isExpanded: false, formData: { firstname: '', lastname: '' } }; toggleExpand = () => { this.setState(prevState => ({ isExpanded: !prevState.isExpanded })); }; handleInputChange = (e) => { const { name, value } = e.target; this.setState(prevState => ({ formData: { ...prevState.formData, [name]: value } })); }; render() { const { isExpanded, formData } = this.state; return ( <div className="accordion-container"> <div className="dropdown-header" onClick={this.toggleExpand}> <h4 className="dropdown-text">Shipping Information</h4> <span className="dropdown-selection">{isExpanded ? '-' : '+'}</span> </div> {isExpanded && ( <div className="wrapper"> <div className="row"> <div className="col-md-6"> <div className="info-group mb-3"> <label>First name</label> <input type="text" className="info-input" name="firstname" value={formData.firstname} onChange={this.handleInputChange} /> </div> </div> <div className="col-md-6"> <div className="info-group mb-3"> <label>Last name</label> <input type="text" className="info-input" name="lastname" value={formData.lastname} onChange={this.handleInputChange} /> </div> </div> {/* 其他表单元素 */} </div> </div> )} </div> ); } } export default ShippingInfoAccordion;
父组件中直接使用
import React from 'react'; import ShippingInfoAccordion from './ShippingInfoAccordion'; import ShippingOptionsAccordion from './ShippingOptionsAccordion'; const CheckoutPage = () => { return ( <div className="checkout-container"> <ShippingInfoAccordion /> <ShippingOptionsAccordion /> </div> ); }; export default CheckoutPage;
额外优化:封装通用表单输入组件
如果表单元素重复较多,可以进一步封装通用Input组件,减少重复代码:
import React from 'react'; const FormInput = ({ label, name, value, onChange, type = 'text' }) => { return ( <div className="info-group mb-3"> <label>{label}</label> <input type={type} className="info-input" name={name} value={value} onChange={onChange} /> </div> ); }; export default FormInput;
之后在内容组件中直接使用:
<FormInput label="First name" name="firstname" value={formData.firstname} onChange={this.handleInputChange} />
内容的提问来源于stack exchange,提问作者Yaya
相关产品推荐
相关产品推荐

