函数组件input失去聚焦的坑

函数组件 input 失去聚焦的坑

这是一个很容易遇见的问题,每输入一个字符 Input 的焦点就没了,本文将就此问题做分析和介绍一种解决方法。

出现的原因可能是你在组件的render函数中用了通过函数生成的 Input 组件,具体请看分析。

如果你遇见该种问题时并没有使用函数式组件,请告知,并一起思考解决方案。

在向 Input 组件里输入内容的过程中不要让它触发 render,把这个触发操作放在输入结束后,手动的点击按钮或者待它失去焦点(onBlur),就是不使用 onChange 事件。

或者还是双向绑定的写法。使用 onChange。但状态放在 useRef 中。

本文涉及的现象及常见的原因

一般情况下在react框架下使用 Input 组件时,不管是跟着教程或者是网络搜索的用法,常见如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default class Test extends Component {
onChange = (e) => {
this.setState({
value: e.target.value,
});
};
render() {
return (
<div>
<Input onChange={this.onChange} value={this.state.value}></Input>
</div>
);
}
}

纵观搜索到的资料,基本都是这种用法,这种用法当然没问题,是一种很标准的用法,但是当它遇到函数式组件的时候会出现每次输入都会失去焦点的问题,

函数式组件?

1
2
3
4
5
6
7
8
render() {
let input = <Input onChange={this.onChange} value={this.state.value}></Input>
return (
<div>
{input}
</div>
)
}

就是说当你的组件中需要用逻辑来控制渲染什么组件的时候会用一个变量指向一个函数,该函数返回一个组件,这个逻辑中可能会有 switch 或者若干个 if 语句。

此时!每次 render 的时候,相当于都要调用这个函数来重新生成一个组件用于渲染,也就是说这时候的组件已经不是上次渲染出的组件了,当然会出现这种没有焦点的情况了。

解决方案

实际的做法:

在向 Input 组件里输入内容的过程中不要让它触发 render,把这个触发操作放在输入结束后,手动的点击按钮或者待它失去焦点(onBlur),就是不使用 onChange 事件。

或者还是双向绑定的写法。使用 onChange。但状态放在 useRef 中。

摆烂的做法:

如果你看到了这里,说明你确实使用了函数式组件,在这种情况下,你可以参考下文中的方案,希望可以有所帮助。

有些文章提出的解决方案是不要用函数式组件,这不就是经典的“既然解决不了问题,就解决制造问题的人”的例子嘛?目前可供参考的解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
export default class Test extends Component {
onChange = (e) => {
this.inputValue = e.target.value;
};
onBlur = () => {
this.setState({
value: this.inputValue,
});
};
render() {
return (
<div>
<Input
onChange={this.onChange}
// 在失去焦点的时候再setState如果业务允许增加一个按钮也可以放在按钮的click事件里
onBlur={this.onBlur}
// 这种方法在setState之后重新生成的Input组件里面的内容就没了可以用defaultValue重新加载上次的值
defaultValue={this.state.value}
></Input>
//
如果业务允许增加一个按钮的话,可以把setState方法放在按钮的click事件里。
<Button onClick={this.onBlur}>提交</Button>
</div>
);
}
}