开发者问题收集

通过数组进行映射并在React中渲染指定的组件

2018-03-28
2161

我有 2 个几乎相同的组件,它们通过选项数组进行映射并生成复选框或单选按钮。组件之间的唯一区别是呈现的子组件(复选框或单选输入)。

我想减少这些组件中的重复代码,但我不确定解决它的最佳方法。我可以将 2 个组件合并为一个组件,例如 FormControlGroup ,并添加更多 props 以允许我选择是否要呈现复选框或单选按钮,例如 checkboxOrRadio ,但这意味着如果我添加复选框或单选按钮的新变体,例如 CustomCheckbox ,我将不得不继续扩展此组件的 props。

<FormControlGroup
  label="Radio buttons"
  name="test"
  options=[{label: 'one', value: 1}, {label: 'two', value: 2}, {label: 'three', value: 3}]
  checkboxOrRadio="radio"
/>

是否可以(并且合理地)将组件作为 prop 传入并在 map 函数中呈现该组件? 如果可以,我该怎么做?或者有更优雅的解决方案?这样,我可以传入任何我想要的组件,它将被呈现,并将 key、name、label、onChange、value、checked 属性传递给它。

CheckboxGroup.js

import React from 'react';
import CheckboxInput from './CheckboxInput';

const CheckboxGroup = ({ label, name, options, onChange, children }) => {
  return (
    <div className="form-group form-inline">
      <span className="faux-label">{label}</span>

      {children}

      <div className="form-inline__field-container">
        {options &&
          options.map(option => (
            <CheckboxInput
              key={option.value}
              name={name}
              label={option.label}
              onChange={onChange}
              value={option.value}
              checked={option.value}
            />
          ))
        }
      </div>
    </div>
  );
};

export default CheckboxGroup;

RadioGroup.js

import React from 'react';
import RadioInput from './RadioInput';

const RadioGroup = ({ label, name, options, onChange, children }) => {
  return (
    <div className="form-group form-inline">
      <span className="faux-label">{label}</span>

      {children}

      <div className="form-inline__field-container">
        {options &&
          options.map(option => (
            <RadioInput
              key={option.value}
              name={name}
              label={option.label}
              onChange={onChange}
              value={option.value}
              checked={option.value}
            />
          ))
        }
      </div>
    </div>
  );
};

export default RadioGroup;
3个回答

在某些情况下,将组件作为 prop 传递是绝对明智的。事实上,这是许多 React 库中使用的模式,包括 React Router,它允许您将 component prop 传递给 Route 组件

在您的情况下, FormControlGroup 组件的 render 函数可能看起来像这样:

render({component, ...}) { // component is a prop
  const InputComponent = component;
  return (
    ... // outer divs
    { options.map(option =>
      <InputComponent key={option.value} ... />
    }
    ...
  )
}

然后您可以像这样使用它:

<FormControlGroup
  label="Radio buttons"
  name="test"
  options=[{label: 'one', value: 1}, {label: 'two', value: 2}, {label: 'three', value: 3}]
  component={CheckboxInput}
/>

另一个选项是创建一个新组件,负责渲染外部 <div> 元素,然后将 options 映射到某个外部组件中的输入组件列表。这样您就可以减少对任何给定输入组件应期望的 props 的假设。由于您已经在使用 children ,因此您必须将其拆分为两个组件。以下是其中一种可能的情况:

const FormControlGroup = ({ label, children }) => {
  return (
    <div className="form-group form-inline">
      <span className="faux-label">{label}</span>
      {children}
    </div>
  );
};

const FormControlOptions = ({ children }) => {
  return (
    <div className="form-inline__field-container">
      {children}
    </div>
  );
};

const SomeOuterComponent = ({ label, name, options, onChange }) => {
  <FormControlGroup label={label}>
    ... // other children
    <FormControlOptions>
      {
        options.map(option =>
          <CheckboxInput
            key={option.value}
            name={name}
            label={option.label}
            onChange={onChange}
            value={option.value}
            checked={option.value}
          />
        )
      }
    </FormControlOptions>
  </FormControlGroup>
}

当然,有很多方法可以设计它。您采用的具体实现将取决于您的用例。

ethan.roday
2018-03-28

在我看来,这似乎不是一个坏主意。这绝对是可行的,也许这不是最优雅的解决方案,但我目前看不出它有什么问题。

Theo Wittkovskiy
2018-03-28

我个人不会将其更改为 FormControlGroup 组件,因为这样可以简化使用该组件的代码。这样您就可以快速知道 CheckboxGroup 与 RadioGroup 的区别。

更改它意味着每次都要检查 checkboxOrRadio prop,以准确查看您正在更改的组件。

我想说,等一下,如果您开始以完全相同的方式获取更多想要的元素,那么创建一个通用组件。但对于仅共享一些代码的两个组件来说,这并不是什么大问题。

Bradey Whitlock
2018-03-28