我正在学习React,并决定尝试创建一个具有不同输入的表单。在复制粘贴所有不同输入类型的标签和输入10次后,我觉得我应该尝试创建一个组件,根据传递给它的道具来呈现不同的输入
我创建了以下组件,它可以很好地用于文本、密码、电子邮件、数字等输入。我是这样使用的:
<FormGroup
inputType="text"
inputName="firstName"
inputPlaceholder="First Name"
</FormGroup>
这是组件:
const FormGroup = (props) => {
return (
<div className="form-group">
<label className="form-label" htmlFor={props.inputName}>
<p>{props.inputPlaceholder}</p>
</label>
<input
type={props.inputType}
name={props.inputName}
placeholder={props.inputPlaceholder}
/>
</div>
);
};
export default FormGroup;
问题是,当我开始考虑上传、范围、复选框、日期、范围等输入时,我就开始怀疑创建一个可以处理任何输入类型的通用输入组件是否可行。也许组件会变得太大/太复杂/太混乱。我应该继续尝试创建这样的通用输入组件,还是尝试其他方法?
可以
不,你(可能)不应该。
从技术上讲,把这些放在一起是没有限制的,对于非常相似的输入(文本输入、日期输入、数字输入),这实际上可能是一件好事。
然而,当你跳到像<select>
这样的元素时,它的道具非常不同,这不仅会使你的组件的内部更加复杂,而且消耗你的通用组件的组件也更加复杂,imo是一个更重要的考虑因素。
在大多数典型的web项目中,我通常有以下组件:
<Input />
(支持文本、数字和日期)<Select />
- CCD_ 4和CCD_
- CCD_ 6和CCD_
<Upload />
——自己的野兽
这是可行的,但随着对更多类型的支持,它会变得非常复杂。
对于表单处理,您最好使用一个同时管理输入状态的库。
Formik目前是一个受欢迎且可靠的选择https://formik.org/
试着浏览他们的文档,即使你决定不使用它,它也会让你更好地了解你试图实现的要求
编程中有一个原则称为"单独责任原则",它将帮助您更好地构建代码。保持简单!我看到的第一个问题是,您的组件正在执行多个任务。它确实显示了一个表单组,它将元素分组在一起(子元素),就像标签和表单元素一样。但它继续显示实际的标签和输入(其他类型的表单元素呢?)。它应该只是一个包装器。
<input>
已经接受不同类型的输入。但是FormGroup不仅可以接受输入,还可以接受其他东西,比如select和not。因此,您将增加组件的复杂性。
Javascript很棒,它是允许的,你可以做任何事情。Imageine在某个时候,您将决定将Typescript添加到您的项目中。或者更好的是,您需要为您的组件编写测试。你打算如何测试这样一个怪物组件。把这样的东西分组是很好的,它可以为你节省一些时间,但在某个时候,你会想自由地添加你小时候想要的任何东西。现在,每次您想在组件下添加不同的内容时,都必须修改组件。同样,它应该只是一个包装器。
最后,总的来说,当你把if添加到你的组件中时(你必须在某个时候添加if,如果我正确理解你要去的地方),这是一个信号,表明你的组件有很多违反单一责任原则的行为,问问自己,把它分为两个或多个组件是否更好。我看到过这样的代码,其中有一个组件将采用布尔值,无论我们传递true还是false,都将呈现这个或那个jsx。我们在每种情况下传递的道具也会有所不同。这是重构的一个很好的候选者。。。
哦,还有一件事需要注意。您可能想要使用reatsrap(假设您使用的是bootstrap)。它有一个FormGroup和其他任何东西。您不必自己创建这些组件。
使用儿童还是道具?
有时,你可能会想,为什么每次都要麻烦传递孩子,尤其是当一遍又一遍都是相同的代码时。这违背了DRY。。。而这正是你想要避免的。但是你失去了对孩子们的控制。如果你想把一些类添加到输入、标签或其他任何东西中,你也必须通过道具来传递这些。。。labelClasses,inputClasses。
让我们举一个例子,一个antd表:
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
<Table dataSource={dataSource} columns={columns} />;
好吧,这太棒了。我不必自己重复这些专栏了。但是,您可以对这些列执行的操作有些有限。
然而,有了这个:
<Table dataSource={dataSource}>
<Column></Column>
</Table>
我可以将Column包装成一个样式组件:
const MyStyledColumn = styled(Column)``
<Table dataSource={dataSource}>
<MyStyledColumn></MyStyledColumn>
</Table>
很酷。