我一直在想我想在我的代码库中创建一个抽象,这将消除很多样板。我的问题是关于实现子类和父类之间交互的最“正确”的方法。
我想要将很多<table />
抽象为一种<Table />
组件。这样做的原因是我们有很多样板可以处理可排序的标题,分页等。每次我们实现一个新表时,都会有很多复制粘贴和许多额外的测试,这些测试应该真正抽象出来
我的理想模式是:
<Table>
<Table.Header>
<Table.SortableHeader dataKey="id" default>ID</Table.SortableHeader>
<Table.SortableHeader dataKey="name">Name</Table.SortableHeader>
// ...
</Table.Header>
<Table.PaginatedBody pageSize=15 rowElement={ MyRowElement } />
</Table>
为了做到这一点,<Table.SortableHeader>
组件需要能够设置与父<Table>
组件的状态(或以其他方式交互),以便更改其排序键/顺序,以及排序键/顺序需要传递给<Table.PaginatedBody>
组件。
此外,<Table.SortableHeader>
组件需要知道当前的排序键/顺序,因为它们将显示不同,具体取决于排序键是否与其dataKey
相同,以及排序顺序是否为{ {1}}或asc
。
我想到这样做的一种方法是通过在desc
中传递父组件(我知道新的基于上下文的东西已经出来了,但这是一个更普遍的原则问题)。
这种方法是否会引发任何明显的问题,还有其他标准方法可以做这种事情吗?我想避免使用我传递给context
组件的配置对象,然后生成结构,因为我觉得JSX是一个非常好的用于创建视图元素的DSL,而且这更加清晰。
答案 0 :(得分:1)
您可以在Header
组件中定义排序处理程序,并将其与排序状态一起添加到子项道具中。这种方式Table
组件可以调用父排序处理程序来更新Header
状态,然后将排序状态传递给cloneElement
道具。
您可以使用children
向{ React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {
sort: this.state.sort,
handleSort: this.handleSort
});
})}
添加道具:
import {Component, NgModule, VERSION} from '@angular/core'
import { ReactiveFormsModule, FormGroup, FormBuilder, Validators } from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser'
function MustStartWithValidator (str: string) {
return (control: SimpleControl) => {
if (!control.value.startsWith(str)) {
return {'mustStartWith': true};
}
return false;
}
}
@Component({
selector: 'my-app',
template: `
<button type="button" (click)="toggleValidation()">{{btnText()}}</button>
<form [formGroup]="form">
<input formControlName="myInput" type="text">
</form>
<div>Form isValid: {{form.valid}}</div>
<div>Form hasError mustStartWith: {{form.hasError('mustStartWith')}}</div>
<div>Form errors: {{form.errors | json}}</div>
<div>Control isValid: {{form.get('myInput').valid}}</div>
<div>Control hasError mustStartWith: {{form.get('myInput').hasError('mustStartWith')}}</div>
<div>Control errors: {{form.get('myInput').errors | json}}</div>
`,
})
export class App {
shouldValidate = true;
form: FormGroup;
constructor(fb: FormBuilder) {
this.form = fb.group({
myInput: ['', MustStartWithValidator('test')]
})
}
btnText () {
if (this.shouldValidate) {
return 'Disable validation';
}
return 'Enable validation';
}
toggleValidation () {
this.shouldValidate = !this.shouldValidate;
const control = this.form.get('myInput');
if (this.shouldValidate) {
control.setValidators(MustStartWithValidator('test'));
} else {
control.clearValidators();
}
control.updateValueAndValidity();
}
}
@NgModule({
imports: [ BrowserModule, ReactiveFormsModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}