【发布时间】:2016-10-15 03:14:24
【问题描述】:
我有一个接口,它是<input>s 的列表。在其中一个输入中按回车键应将焦点移至下一个输入,如果您已经在最后一个输入上,则应添加另一个输入并聚焦。项目列表由 redux 管理。
这里是做这个纯粹部分的代码,没有焦点:
class ListItem extends Component {
render() {
return (
<li>
<input
defaultValue={this.props.value}
onKeyUp={this.onKeyUp.bind(this)}
ref={(input) => this.input = input}
/>
</li>
);
}
onKeyUp(event) {
this.props.onChange(event.target.value, event.keyCode === 13);
}
focus() {
this.input.focus();
}
}
class List extends Component {
render() {
return (
<ul>
{this.props.items.map((item, i) =>
<ListItem
key={i}
value={item}
onChange={(value, enterPressed) => this.onChange(i, value, enterPressed)}
/>
)}
</ul>
);
}
onChange(i, value, enterPressed) {
this.props.dispatch({
type: 'UPDATE_ITEM',
index: i,
value: value
});
if (enterPressed && i === this.props.items.length - 1) {
this.props.dispatch({
type: 'ADD_ITEM'
});
}
}
}
这看起来很棘手,因为当我们想要聚焦它时,下一个列表元素可能还不存在,所以我们需要等到 redux 状态发生变化,并且列表会使用最后一个项目重新呈现。
我能想到的唯一方法是为每个列表项存储一个 ref 数组,然后在按下 enter 时调度 redux 事件并将焦点列表项的索引设置为组件状态。然后,在 componentDidUpdate 中(将在 redux 状态更新并且额外的输入在 DOM 中后调用),检查状态以查看我们应该关注哪个输入,并对其调用 focus 方法。
class List extends React.Component {
constructor(props) {
super(props);
this.inputs = [];
}
render() {
return (
<ul>
{this.props.items.map((item, i) =>
<ListItem
key={i}
value={item}
onChange={(value, enterPressed) => this.onChange(i, value, enterPressed)}
ref={(input) => this.inputs[i] = input}
/>
)}
</ul>
);
}
onChange(i, value, enterPressed) {
this.props.dispatch({
type: 'UPDATE_ITEM',
index: i,
value: value
});
if (enterPressed) {
this.setState({
inputToFocus: i + 1
})
if (i === this.props.items.length - 1) {
this.props.dispatch({
type: 'ADD_ITEM'
});
}
}
}
componentDidUpdate() {
if (typeof this.state.inputToFocus === 'number') {
this.inputs[this.state.inputToFocus].focus();
this.setState({
inputToFocus: null
});
}
}
这感觉真的很脆弱和丑陋。有没有更好的方法?
【问题讨论】:
标签: javascript reactjs redux react-redux