映射数组并在React

时间:2018-03-28 15:46:10

标签: javascript reactjs

我有2个几乎相同的组件,它们映射了一系列选项并生成复选框或单选按钮。组件之间的唯一区别是呈现的子组件(复选框或无线电输入)。

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

<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 个答案:

答案 0 :(得分:1)

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

在您的情况下,render组件的FormControlGroup功能可能如下所示:

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映射到某个外部组件中的输入组件列表。这允许您对任何给定输入组件应该期望的道具做出更少的假设。由于您已经在使用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>
}

当然,有很多方法可以设计它。您使用的确切实施将取决于您的使用案例。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我个人不会将其更改为FormControlGroup组件,因为它使您在使用该组件的代码中更简单。因此,您可以快速了解什么是CheckboxGroup与RadioGroup。

更改它意味着每次都要检查checkboxOrRadio prop,以确切了解您要更改的组件。

我说等等,如果你开始以完全相同的方式获得更多元素,那么创建一个通用组件。但是,仅仅分享一些代码的两个组件并不是什么大问题。