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

如何在ReactJS中创建通用组件以减少重复组件的编写?

如何创建可复用的React列表选择组件

嘿,很高兴帮你解决这个组件复用的问题!你已经写了两个高度相似的选择列表组件,现在要把它们抽象成一个通用的版本,核心思路就是把变化的部分抽成组件的props参数,比如请求URL、select的name属性这些,而不变的逻辑(比如获取数据、渲染选项)留在组件内部复用。

步骤1:编写可复用的CustomListComponent

我们把重复的逻辑保留,将需要动态调整的参数通过props传入:

import { Component } from 'react';

class CustomListComponent extends Component {
  constructor(props) {
    super(props);
    this.state = { options: [] };
  }

  componentDidMount() {
    // 从props中获取请求地址,替代原来硬编码的URL
    fetch(this.props.reqUrl, { method: 'GET' })
      .then(response => response.json())
      .then(data => {
        this.setState({ options: data });
      })
      // 建议加上错误处理,避免请求失败导致页面异常
      .catch(error => console.error('获取列表数据失败:', error));
  }

  render() {
    // 从props中获取select的name和样式类,样式类可以设置默认值
    const { selectName, selectClass = 'form-control' } = this.props;
    const { options } = this.state;

    return (
      <select name={selectName} className={selectClass}>
        {/* 可以默认添加空选项,提升用户体验 */}
        <option value="">请选择</option>
        {options.map(item => (
          <option key={item.id} value={item.code}>
            {item.name}
          </option>
        ))}
      </select>
    );
  }
}

export default CustomListComponent;

步骤2:使用CustomListComponent替代原有组件

现在你只需要通过传递不同的props,就能生成原来的两个选择列表:

<div class="form-group">
  <CustomListComponent reqUrl="/api/get-code-list/" selectName="code_list" />
</div>
<div class="form-group">
  <CustomListComponent reqUrl="/api/get-location-list/" selectName="location_list" />
</div>

额外优化建议(可选)

为了让组件更通用,适配更多场景,你还可以扩展更多props:

  • 如果不同接口返回的字段名不一样(比如有的用value而非code,label而非name),可以添加valueKey和labelKey props,设置默认值
  • 添加加载状态提示,避免数据未返回时用户看到空列表
  • 支持传入占位符文本

优化后的组件示例:

class CustomListComponent extends Component {
  constructor(props) {
    super(props);
    this.state = { options: [], isLoading: true };
  }

  componentDidMount() {
    const { reqUrl } = this.props;
    fetch(reqUrl, { method: 'GET' })
      .then(response => response.json())
      .then(data => {
        this.setState({ options: data, isLoading: false });
      })
      .catch(error => {
        console.error('获取列表数据失败:', error);
        this.setState({ isLoading: false });
      });
  }

  render() {
    const { 
      selectName, 
      selectClass = 'form-control',
      valueKey = 'code',
      labelKey = 'name',
      placeholder = '请选择'
    } = this.props;
    const { options, isLoading } = this.state;

    // 加载状态下显示禁用的加载提示
    if (isLoading) {
      return <select className={selectClass} disabled><option>加载中...</option></select>;
    }

    return (
      <select name={selectName} className={selectClass}>
        <option value="">{placeholder}</option>
        {options.map(item => (
          <option key={item.id} value={item[valueKey]}>
            {item[labelKey]}
          </option>
        ))}
      </select>
    );
  }
}

这样即使遇到不同格式的接口,你也能灵活使用:

<CustomListComponent 
  reqUrl="/api/get-category-list/" 
  selectName="category_list"
  valueKey="id"
  labelKey="categoryName"
  placeholder="请选择分类"
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:36:36