在 React 中需要类似 event.target.focus() 的东西
need something like event.target.focus() in React
我正在创建一个动态列表组件,基本上每次向列表中添加内容时都会呈现一个新的空文本字段。该组件如下(它使用自定义的 TextFieldGroup 但我认为代码不是必需的,因为没有发生任何异常情况。):
const DynamicInputList = ({ inputs, onChangeArray, label, name, errors }) =>
{
const nonEmptyInputs = inputs.filter(input => {
return input !== "";
});
const lastIndex = nonEmptyInputs.length;
return (
<div>
{nonEmptyInputs.map((input, index) => {
return (
<Grid container spacing={16} key={index}>
<Grid item xs={12}>
<TextFieldGroup
label={label}
id={`${name}${index}`}
name={name}
value={input}
onChange={e => onChangeArray(e, index)}
errors={errors[name]}
/>
</Grid>
</Grid>
);
})}
<Grid container spacing={16} key={lastIndex}>
<Grid item xs={12}>
<TextFieldGroup
label={label}
id={`${name}${lastIndex}`}
name={name}
value={inputs[lastIndex]}
onChange={e => onChangeArray(e, lastIndex)}
errors={errors[name]}
/>
</Grid>
</Grid>
</div>
);
};
onChangeArray函数如下:
onChangeArray = (e, index) => {
const state = this.state[e.target.name];
if (e.target.value === "") {
state.splice(index, 1);
this.setState({ [e.target.name]: state });
} else {
state.splice(index, 1, e.target.value);
this.setState({ [e.target.name]: state });
}
};
一切正常,除非更改空白字段(开始键入)时它会立即从任何字段中移除焦点。我正在寻找一种方法来保持对这个领域的关注,同时仍然在下面添加新的领域。
提前致谢。
问题是您遇到了以下事件序列(假设 inputs
长度为 5):
- React 呈现 1 个字段(键 = 5)
- 用户开始输入 'a'
- 您的状态更改已触发
- React 呈现 2 个全新的字段 (key = 1 & value = 'a', key = 5) 并丢弃旧字段 (key = 5)
至少有两种解法
不要删除/触发原始字段的重新呈现
这是更清洁的解决方案。
首先,您使用 slice
直接改变 onChangeArray
中的状态,因为 that does an in-place modification。也许这现在不会引起问题,但它是一个很大的 React 反模式,可能会产生不可预测的行为。
这是一个快速修复:
onChangeArray = (e, index) => {
const state = [...this.state[e.target.name]];
if (e.target.value === "") {
state.splice(index, 1);
this.setState({ [e.target.name]: state });
} else {
state.splice(index, 1, e.target.value);
this.setState({ [e.target.name]: state });
}
};
我将把实现的修改留给你,但要点是:
- 使用一致的
key
引用,这意味着遍历所有 inputs
并跳过空的而不是先找到空的然后将任意键设置为总长度。当然,您仍然应该渲染 第一个 空的
- 您可以考虑渲染所有内容,并根据需要使用 CSS
display:none
属性来实现您想要的 UX
利用 input
的 autofocus
属性
我假设您的 TextFieldGroup
使用 input
元素。您可以将 autofocus
attribute 传递给您想要获得焦点的字段。这回答了你原来的问题。
但不推荐这样做,因为您仍然不必要地 运行 通过那些重新渲染周期,然后在上面放置一个补丁。
我正在创建一个动态列表组件,基本上每次向列表中添加内容时都会呈现一个新的空文本字段。该组件如下(它使用自定义的 TextFieldGroup 但我认为代码不是必需的,因为没有发生任何异常情况。):
const DynamicInputList = ({ inputs, onChangeArray, label, name, errors }) =>
{
const nonEmptyInputs = inputs.filter(input => {
return input !== "";
});
const lastIndex = nonEmptyInputs.length;
return (
<div>
{nonEmptyInputs.map((input, index) => {
return (
<Grid container spacing={16} key={index}>
<Grid item xs={12}>
<TextFieldGroup
label={label}
id={`${name}${index}`}
name={name}
value={input}
onChange={e => onChangeArray(e, index)}
errors={errors[name]}
/>
</Grid>
</Grid>
);
})}
<Grid container spacing={16} key={lastIndex}>
<Grid item xs={12}>
<TextFieldGroup
label={label}
id={`${name}${lastIndex}`}
name={name}
value={inputs[lastIndex]}
onChange={e => onChangeArray(e, lastIndex)}
errors={errors[name]}
/>
</Grid>
</Grid>
</div>
);
};
onChangeArray函数如下:
onChangeArray = (e, index) => {
const state = this.state[e.target.name];
if (e.target.value === "") {
state.splice(index, 1);
this.setState({ [e.target.name]: state });
} else {
state.splice(index, 1, e.target.value);
this.setState({ [e.target.name]: state });
}
};
一切正常,除非更改空白字段(开始键入)时它会立即从任何字段中移除焦点。我正在寻找一种方法来保持对这个领域的关注,同时仍然在下面添加新的领域。
提前致谢。
问题是您遇到了以下事件序列(假设 inputs
长度为 5):
- React 呈现 1 个字段(键 = 5)
- 用户开始输入 'a'
- 您的状态更改已触发
- React 呈现 2 个全新的字段 (key = 1 & value = 'a', key = 5) 并丢弃旧字段 (key = 5)
至少有两种解法
不要删除/触发原始字段的重新呈现
这是更清洁的解决方案。
首先,您使用 slice
直接改变 onChangeArray
中的状态,因为 that does an in-place modification。也许这现在不会引起问题,但它是一个很大的 React 反模式,可能会产生不可预测的行为。
这是一个快速修复:
onChangeArray = (e, index) => {
const state = [...this.state[e.target.name]];
if (e.target.value === "") {
state.splice(index, 1);
this.setState({ [e.target.name]: state });
} else {
state.splice(index, 1, e.target.value);
this.setState({ [e.target.name]: state });
}
};
我将把实现的修改留给你,但要点是:
- 使用一致的
key
引用,这意味着遍历所有inputs
并跳过空的而不是先找到空的然后将任意键设置为总长度。当然,您仍然应该渲染 第一个 空的 - 您可以考虑渲染所有内容,并根据需要使用 CSS
display:none
属性来实现您想要的 UX
利用 input
的 autofocus
属性
我假设您的 TextFieldGroup
使用 input
元素。您可以将 autofocus
attribute 传递给您想要获得焦点的字段。这回答了你原来的问题。
但不推荐这样做,因为您仍然不必要地 运行 通过那些重新渲染周期,然后在上面放置一个补丁。