将Angular组件从许多输入/输出重构为单个配置对象 [英] Refactoring Angular components from many inputs/outputs to a single config object
问题描述
我的组件通常从具有多个@Input
和@Output
属性开始.当我添加属性时,切换到单个配置对象作为输入似乎更干净.
My components often start out by having multiple @Input
and @Output
properties. As I add properties, it seems cleaner to switch to a single config object as input.
例如,这是一个具有多个输入和输出的组件:
For example, here's a component with multiple inputs and outputs:
export class UsingEventEmitter implements OnInit {
@Input() prop1: number;
@Output() prop1Change = new EventEmitter<number>();
@Input() prop2: number;
@Output() prop2Change = new EventEmitter<number>();
ngOnInit() {
// Simulate something that changes prop1
setTimeout(() => this.prop1Change.emit(this.prop1 + 1));
}
}
及其用法:
export class AppComponent {
prop1 = 1;
onProp1Changed = () => {
// prop1 has already been reassigned by using the [(prop1)]='prop1' syntax
}
prop2 = 2;
onProp2Changed = () => {
// prop2 has already been reassigned by using the [(prop2)]='prop2' syntax
}
}
模板:
<using-event-emitter
[(prop1)]='prop1'
(prop1Change)='onProp1Changed()'
[(prop2)]='prop2'
(prop2Change)='onProp2Changed()'>
</using-event-emitter>
随着属性数量的增加,似乎切换到单个配置对象可能会更干净.例如,这是一个带有单个配置对象的组件:
As the number of properties grows, it seems that switching to a single configuration object might be cleaner. For example, here's a component that takes a single config object:
export class UsingConfig implements OnInit {
@Input() config;
ngOnInit() {
// Simulate something that changes prop1
setTimeout(() => this.config.onProp1Changed(this.config.prop1 + 1));
}
}
及其用法:
export class AppComponent {
config = {
prop1: 1,
onProp1Changed(val: number) {
this.prop1 = val;
},
prop2: 2,
onProp2Changed(val: number) {
this.prop2 = val;
}
};
}
模板:
<using-config [config]='config'></using-config>
现在,我可以通过多层嵌套组件传递配置对象引用.使用config的组件将调用诸如config.onProp1Changed(...)
之类的回调,这将导致config对象重新分配新值.因此,似乎我们仍然有单向数据流.另外,添加和删除属性不需要更改中间层.
Now I can just pass the config object reference through multiple layers of nested components. The component using the config would invoke callbacks like config.onProp1Changed(...)
, which causes the config object to do the reassignment of the new value. So it seems we still have one-way data flow. Plus adding and removing properties doesn't require changes in intermediate layers.
将单个配置对象作为组件的输入,而不是多个输入和输出,是否有不利之处?避免像这样避免@Output
和EventEmitter
会导致以后出现任何问题吗?
Are there any downsides to having a single config object as an input to a component, instead of having multiple input and outputs? Will avoiding @Output
and EventEmitter
like this cause any issues that might catch up to me later?
推荐答案
我想说对Input
使用单个配置对象可能是可以的,但是您应该始终坚持使用Output
. Input
定义您的组件从外部需要什么,其中一些可能是可选的.但是,Output
完全是组件的业务,应在其中定义.如果您依靠用户来传递这些功能,则要么必须检查undefined
函数,要么就继续调用这些函数,就好像它们总是在config中传递一样;如果有的话,使用这些组件也很麻烦.即使用户不需要它们,也可以定义许多事件.因此,始终在组件中定义您的Output
并发出您需要发出的任何东西.如果用户不将那些事件绑定到函数,那很好.
I would say it could be OK to use single config objects for Input
s but you should stick to Output
s at all the time. Input
defines what your component requires from outside and some of those may be optional. However, Output
s are totally component's business and should be defined within. If you rely on users to pass those functions in, you either have to check for undefined
functions or you just go ahead and call the functions as if they are ALWAYS passed within config which may be cumbersome to use your component if there are too many events to define even if the user does not need them. So, always have your Output
s defined within your component and emit whatever you need to emit. If users don't bind a function those event, that's fine.
此外,我认为对Input
使用单个config
并不是最佳实践.它隐藏了真正的输入,用户可能必须查看代码或文档中的内容才能确定应该传递的内容.但是,如果分别定义了Input
,则用户可以使用语言服务
Also, I think having single config
for Input
s is not the best practice. It hides the real inputs and users may have to look inside of your code or the docs to find out what they should pass in. However, if your Input
s are defined separately, users can get some intellisense with tools like Language Service
此外,我认为它也可能破坏变更检测策略.
Also, I think it may break change detection strategy as well.
让我们看下面的示例
@Component({
selector: 'my-comp',
template: `
<div *ngIf="config.a">
{{config.b + config.c}}
</div>
`
})
export class MyComponent {
@Input() config;
}
让我们使用它
@Component({
selector: 'your-comp',
template: `
<my-comp [config]="config"></my-comp>
`
})
export class YourComponent {
config = {
a: 1, b: 2, c: 3
};
}
对于单独的输入
@Component({
selector: 'my-comp',
template: `
<div *ngIf="a">
{{b + c}}
</div>
`
})
export class MyComponent {
@Input() a;
@Input() b;
@Input() c;
}
让我们用这个
@Component({
selector: 'your-comp',
template: `
<my-comp
[a]="1"
[b]="2"
[c]="3">
</my-comp>
`
})
export class YourComponent {}
如上所述,您必须查看YourComponent
的代码以查看要传入的值.此外,还必须在所有位置键入config
才能使用这些Input
.另一方面,您可以清楚地看到在第二个示例中更好地传递了哪些值.如果您使用的是语言服务
As I stated above, you have to look at the code of YourComponent
to see what values you are being passed in. Also, you have to type config
everywhere to use those Input
s. On the other hand, you can clearly see what values are being passed in on the second example better. You can even get some intellisense if you are using Language Service
另一件事是,第二个示例将更好地扩展.如果需要添加更多Input
,则必须一直编辑config
,这可能会破坏组件.但是,在第二个示例中,很容易添加另一个Input
,并且您无需触摸工作代码.
Another thing is, second example would be better to scale. If you need to add more Input
s, you have to edit config
all the time which may break your component. However, on the second example, it is easy to add another Input
and you won't need to touch the working code.
最后但并非最不重要的一点是,您无法真正以自己的方式提供双向绑定.您可能知道,如果在Input
中名为data
和Output
中名为dataChange
,则组件的使用者可以使用双向绑定糖语法和简单类型
Last but not least, you cannot really provide two-way bindings with your way. You probably know that if you have in Input
called data
and Output
called dataChange
, consumers of your component can use two-way binding sugar syntax and simple type
<your-comp [(data)]="value">
当您使用
this.dataChange.emit(someValue)
希望这可以澄清我对单个Input
Hope this clarifies my opinions about single Input
修改
我认为单个Input
存在一个有效的情况,其中内部也定义了一些function
.如果您要开发类似图表组件的程序,而该程序通常需要复杂的选项/配置,那么最好使用单个Input
.这是因为该输入设置一次且永不更改,因此最好将图表选项放在一个位置.此外,用户可能会传递一些功能来帮助您绘制图例,工具提示,x轴标签,y轴标签等.
像这样的输入在这种情况下会更好
I think there is a valid case for a single Input
which also has some function
s defined inside. If you are developing something like a chart component which often requires complex options/configs, it is actually better to have single Input
. It is because, that input is set once and never changes and it is better to have options of your chart in a single place. Also, the user may pass some functions to help you draw legends, tooltips, x-axis labels, y-axis labels etc.
Like having an input like following would be better for this case
export interface ChartConfig {
width: number;
height: number;
legend: {
position: string,
label: (x, y) => string
};
tooltip: (x, y) => string;
}
...
@Input() config: ChartConfig;
这篇关于将Angular组件从许多输入/输出重构为单个配置对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!