我有以下组件层次结构:
<Form>
<div>
<Label>
<Input name="first_name" />
</Label>
</div>
<Label>
<Input name="first_name" />
</Label>
</Form
我想实现以下行为:
所有<Form>
个组件都应实现autofocus
第一个<Input>
的行为,而<Input>
不必每次都指定此行为。在每个autofocus
中手动使用<Form>
容易出错,开发人员往往会忘记它。
至于现在,我决定在<Form>
组件中使用这样的代码:
componentDidMount() { $(ReactDOM.findDOMNode(this)).find('input:first:visible').focus() }
<Label>
元素应具有for
/ htmlFor
+ <Input>
属性,该属性与<Input>
id
内的<Label>
cloneElement
匹配1}}没有开发人员每次都必须手动指定它。我正在考虑使用递归for
并注入id
和aria-label
属性,但这听起来太麻烦而且不优雅。
有什么想法吗?
答案 0 :(得分:1)
因此,我认为我们可以通过创建一些自定义组件来完成您正在寻找的内容:Form
和FormGroup
。
Form
将负责在FormGroup
上设置支柱,指明是否应该集中注意力(我假设所有Form
都是孩子是FormGroup
个实例):
class Form extends React.Component {
render() {
const children = React.Children.map(this.props.children, (el, i) => {
const focused = i === 0;
return React.cloneElement(el, { focused });
});
return <form>{children}</form>;
}
}
我们的FormGroup
组件有一些责任。
htmlFor
属性此代码涉及更多:
class FormGroup extends React.Component {
render() {
let input = null;
let label = null;
// Get references to the input and label elements
React.Children.forEach(this.props.children, el => {
switch (el.type) {
case 'input':
input = el;
return;
case 'label':
label = el;
return;
}
});
if (input === null || label === null) {
throw new Error('FormGroup must be used with and input and label element');
}
// Augment: add the htmlFor and autoFocus attributes
label = React.cloneElement(label, { htmlFor: input.props.id });
input = React.cloneElement(input, { autoFocus: this.props.focused });
// Render our augmented instances
return <div>{label}{input}</div>;
}
}
现在我们有了构建块,我们可以创建具有所需行为的表单:
<Form>
<FormGroup>
<label>First Label</label>
<input id="first" type="text" />
</FormGroup>
<FormGroup>
<label>Second Label</label>
<input id="second" type="text" />
</FormGroup>
</Form>
对于此表单,#first
输入将被聚焦,每个标签元素将具有正确的for
属性。
希望这会让你走上正轨。这是此设置的webpackbin:http://www.webpackbin.com/VJVY1a7Tg