Blog Entry

React中每次输入都失焦的一种情况

React中每次输入都失焦的一种情况

Created
2022/01/27
Updated
2022/01/27

React中每次输入都失焦的一种情况

问题

  • 主组件使用函数式组件
  • 子组件使用函数式组件

核心代码:

import { useState } from "react";
export default function Home() {
// 同步值
const [value, setValue] = useState('');
// 响应input输入
const onInput = (value) => {
setValue(value);
};
// 失焦组件,每次输入完都会失去焦点
const InnerInput = ({ n, onInput }) => {
return (
<>
<label>输入3</label>
<input type='text' value={n} onInput={e => onInput(e.target.value)} />
<span>(失焦)</span>
<br />
</>
);
}
return (
<div>
<label>输入1</label>
<input type='text' value={value} onInput={e => onInput(e.target.value)} />
<br />
<label>输入2</label>
<input type='text' value={value} onInput={e => onInput(e.target.value)} />
<br />
<InnerInput n={value} onInput={onInput} />
</div>
)
}

输入1输入2input组件中输入内容时,会相互同步,并且焦点会保持在正在输入的input中;

但在输入3input组件中输入内容时,没输入一个字符,就会失去焦点;

元素分析

为了进一步了解其中发生了什么,我们用Chrome的调试工具观察一下:

可以看到,每次输入时,输入1输入2只有input.value产生了变化,而输入3的每一个组件都是重新渲染的.

这可能要归结到React渲染的问题了,当然这我是无法触及及解决的,只能想想别的办法.

解决

经过一番查阅,有方案是固定组件key,也有使用ref的,不过可能不对应我这种情况,

因为毕竟InnerInput也算一个内部lambda函数,每次调用render调用时,都会生成一个新的InnerInput,那每次都都生成新的组件也就不奇怪了.

所以我试着把InnerInput提取到外面,改为OutterInput,万万没想到可以用了 :dog:

当然,把OutterInput提取到单独的文件中同样有效.

修改后的代码如下:

import { useState } from "react";
const OutterInput = ({ n, onInput }) => {
return (
<>
<label>输入4</label>
<input type='text' value={n} onInput={e => onInput(e.target.value)} />
<br />
</>
);
}
export default function Home() {
// 同步值
const [value, setValue] = useState('');
// 响应input输入
const onInput = (value) => {
setValue(value);
};
// 失焦组件,每次输入完都会失去焦点
const InnerInput = ({ n, onInput }) => {
return (
<>
<label>输入3</label>
<input type='text' value={n} onInput={e => onInput(e.target.value)} />
<span>(失焦)</span>
<br />
</>
);
}
return (
<div>
<label>输入1</label>
<input type='text' value={value} onInput={e => onInput(e.target.value)} />
<br />
<label>输入2</label>
<input type='text' value={value} onInput={e => onInput(e.target.value)} />
<br />
<InnerInput n={value} onInput={onInput} />
<OutterInput n={value} onInput={onInput} />
</div>
)
}