通过数组进行映射并在React中渲染指定的组件
我有 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;
在某些情况下,将组件作为 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>
}
当然,有很多方法可以设计它。您采用的具体实现将取决于您的用例。
在我看来,这似乎不是一个坏主意。这绝对是可行的,也许这不是最优雅的解决方案,但我目前看不出它有什么问题。
我个人不会将其更改为 FormControlGroup 组件,因为这样可以简化使用该组件的代码。这样您就可以快速知道 CheckboxGroup 与 RadioGroup 的区别。
更改它意味着每次都要检查 checkboxOrRadio prop,以准确查看您正在更改的组件。
我想说,等一下,如果您开始以完全相同的方式获取更多想要的元素,那么创建一个通用组件。但对于仅共享一些代码的两个组件来说,这并不是什么大问题。