我有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;
答案 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,以确切了解您要更改的组件。
我说等等,如果你开始以完全相同的方式获得更多元素,那么创建一个通用组件。但是,仅仅分享一些代码的两个组件并不是什么大问题。