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和输入2的input组件中输入内容时,会相互同步,并且焦点会保持在正在输入的input中;
但在输入3的input组件中输入内容时,没输入一个字符,就会失去焦点;
元素分析
为了进一步了解其中发生了什么,我们用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> )}