如果您已经是专业人士,那么也许记得您的拐杖。或者,也许可以为上述问题提供更好的解决方案。
本文将集中于我对如何组织组件组成的个人见解。
从小处开始
让我们考虑一些抽象形式。我们的意思是表单中有很多字段(大约10-15个),但是为了不让眼睛睁开,我们将以一个包含4个字段的表单为例。
以下类型的多层对象到达组件的入口:
const unit = {
name: 'unit1',
color: 'red',
size: {
width: 2,
height: 4,
},
}
一个没有经验的开发人员(像我一样在React工作的第一个月)会在一个组件中完成所有这些工作,输入值将存储在状态中:
const Component = ({ values, onSave, onCancel }) => {
const [ state, setState ] = useState({});
useEffect(() => {
setState(values);
}, [ values, setState ]);
return <div className="form-layout">
<div className="form-field">
<Input onChange={({ target: { value } }) =>
setState((state) => ({...state, name: value }))
}/>
</div>
<div className="form-field">
<Input onChange={({ target: { value } }) =>
setState((state) => ({...state, color: value }))
}/>
</div>
<div className="size">
<div className="form-field">
<Input onChange={({ target: { value } }) =>
setState((state) => ({...state, size: { width: value } }))
}/>
</div>
<div className="form-field">
<Input onChange={({ target: { value } }) =>
setState((state) => ({...state, size: { height: value } }))
}/>
</div>
</div>
<div className="buttons">
<Button onClick={() => onSave(state)}>Save</Button>
<Button onClick={() => onCancel()}>Cancel</Button>
</div>
</div>
}
看到开发人员处理它的速度有多快,客户将提出基于此表单制作另一种表单,但没有“大小”限制。
有2个选项(并且都不正确):
- 您可以复制第一个组件并添加缺少的组件或删除多余的组件。通常,当他们不以自己的组件为基础并且害怕破坏其中的某些组件时,便可以执行此操作。
- 将其他组件设置添加到参数。
如果在3-5个表格实施后项目结束,那么开发人员会很幸运。
但是通常这仅仅是开始,并且不同模具的数量也在不断增加。
然后需要一个类似的对象,但是没有“ color”块。
然后是类似的,但带有一个新的“描述”块。
然后制作一些只读块。
然后,必须将类似的形式插入另一种形式-通常是悲伤,这有时是由悲伤引起的。
复制新表格
采用复制方法的开发人员当然会很快实现新表格。虽然会少于10。但是随后情绪会逐渐下降。
特别是在进行重新设计时。纠正“一点点”形式的块之间的凹痕,更改颜色选择组件。毕竟,不可能一everything而就,而且许多设计解决方案在实施后都必须进行修订。
重要的是要注意经常提及“相似形式”。毕竟,产品是一个,所有模具应该相似。结果,您必须处理非常乏味的常规工作,以对每种形式进行相同的返工,而且,测试人员还需要仔细检查每种形式。
通常,您会明白。请勿复制类似的组件。
归纳新形式
如果开发人员选择了第二条路径,那么他当然会骑马-您可能会认为。它只有几个组件,可以用来绘制许多形状。在整个项目中更正缩进或更改“颜色”部分-这是为了更正代码中的两行,测试人员将不得不在几个地方再次检查。
但是实际上,这条路径催生了一个很难维护的组件。
tk很难使用它。要了解很多参数,要了解每个参数的作用,您需要深入研究。
<Component
isNameVisible={true}
isNameDisabled={true}
nameLabel="Model"
nameType="input"
isColorVisible={true}
isColorDisabled={false}
colorType={'dropdown'}
isSizeVisible={true}
isHeightVisible={true}
isWidthDisabled={false}
/>
这也很难维护。通常,内部存在复杂的交织条件,添加新条件会破坏其他所有条件。调整组件以输出一种形式可能会破坏其余形式。
通常,您会明白。不要使组件具有许多属性。为了解决第二种选择的问题,开发人员从什么开始呢?对。作为真正的开发人员,他们开始开发一些使设置复杂组件变得容易的东西。
例如,它们使fields参数成为可能(就像react-table中的列一样)。字段的参数在那里传递:哪个字段是可见的,哪个字段是不可编辑的,字段的名称。
组件调用变成这样:
const FIELDS = {
name: { visible: true, disabled: true, label: 'Model', type: 'input' },
color: { visible: true, disabled: false, type: 'dropdown' },
size: { visible: true },
height: { visible: true },
width: { disabled: false },
}
<Component
values={values}
fields={FIELDS}
/>
结果,开发人员为自己感到骄傲。他归纳了所有字段的设置并优化了组件的内部代码:现在为每个字段调用一个函数,该函数将配置转换为相应组件的props。即使使用类型名称,也会呈现不同的组件。多一点,您将获得自己的框架。
凉?太多了。
希望它不会变成这样:
const FIELDS = {
name: getInputConfig({ visible: true, disabled: true, label: 'Model'}),
color: getDropDownConfig({ visible: true, disabled: false}),
size: getBlockConfig({ visible: true }),
height: getInputNumberConfig({ visible: true }),
width: getInputNumberConfig({ disabled: false }),
}
<Component
values={values}
fields={FIELDS}
/>
通常,您会明白。不要重新发明轮子。
通过合成零部件和嵌套形状来形成新形状
让我们记住我们仍然在写什么。我们已经有一个反应库。无需发明任何新设计。使用JSX标记描述了react中的组件配置
const Form1 = ({ values }) => {
return <FormPanel>
<FormField disabled label=”Model”>
<Input name="name" />
</FormField>
<FormField disabled label=”Color”>
<DropDown name="color" />
</FormField>
<FormPanel>
<FormField disabled label="Height">
<Input name="height" />
</FormField>
<FormField disabled label="Width">
<Input name="width" />
</From Field>
</FormPanelt>
</FormPanel>
}
看来我们回到了第一个复制选项。但实际上没有。这种组合消除了前两种方法的问题。
有一组用砖组装的模板。每个砖块负责不同的事物。一些用于布局和外观,一些用于数据输入。
如果您需要在整个项目中更改缩进,那么在FormField组件中就足够了。如果您需要更改下拉列表的工作方式,则可以在DropDown组件的一处完成。
如果需要类似的形状,例如,没有“颜色”字段,则可以将通用块放在单独的砖块中,然后组装另一个形状。
我们将Size块移到一个单独的组件中:
const Size = () => <FormPanel>
<FormField disabled label="Height">
<Input name="height" />
</FormField>
<FormField disabled label=”Width”>
<Input name="width" />
</From Field>
</FormPanel>
用各种颜色制作形状:
const Form1 = () => <FormPanel>
<FormField disabled label="Color">
<DropDown name="color" />
</FormField>
<FormField disabled label="Model">
<Input name="name" />
</FormField>
<Size name="size" />
</FormPanel>
我们做出相似的形状,但是没有选择颜色:
const Form2 = () => <FormPanel>
<FormField disabled label="Model">
<Input name="name" />
</FormField>
<Size name="size" />
</FormPanel>
最重要的是,获得这种代码的人不需要处理前任的虚构配置。一切都是用JSX编写的,任何React开发人员都熟悉,每个组件都有参数提示。
通常,您会明白。使用JSX和组件组成。
关于国家的几句话
现在让我们注意状态。更确切地说,他的缺席。一旦添加状态,就关闭数据流,重用组件变得更加困难。所有砖块必须是无状态的(即无状态)。而且只有在最高层,才能将由砖块组装而成的表格连接到状态。如果表单很复杂,则将它分成几个容器并将每个部分连接到redux是有意义的。
不要懒于制作一个单独的无状态表单组件。然后,您将有机会将其用作另一种形式的一部分,或基于它创建一个有状态的形式,或用于连接到redux的容器。
当然,在砖中可能存在一些状态,用于存储与通用数据流不相关的内部状态。例如,在内部状态DropDown(下拉列表)中,可以方便地存储属性(无论是否扩展)。
通常,您会明白。将组件分为无状态和有状态。
总
令人惊讶的是,我经常遇到本文中描述的所有错误以及由此引起的问题。我希望您不再重复它们,然后维护您的代码将变得更加容易。
我将重复要点:
- 请勿复制类似的组件。使用DRY原理。
- 不要使组件具有很多特性和功能。每个组件应负责不同的事情(SOLID的单一职责)
- 将组件分为无状态和有状态。
- 不要重塑您的设计。在组件中使用JSX和合成。