React表单输入单个字符后失焦?重渲染致失焦问题解决咨询
解决React表单输入时每次字符输入后失去焦点的问题
嘿,这个问题我之前也踩过坑!你遇到的输入框每输一个字符就失焦的问题,根源在于你把Finder组件定义在了App组件的内部。
每次App组件因为状态更新(比如你输入字符改变newName)触发重渲染的时候,Finder都会被重新定义成一个全新的组件。这就导致原来的输入框DOM元素被卸载,新的输入框DOM挂载上来,自然就失去焦点了。
下面给你两种简单有效的解决方法:
方法一:将内部组件移到外部,作为独立组件
把Finder组件从App内部抽出来,变成一个独立的组件,然后通过props把需要的状态和回调函数传进去。这样Finder就不会每次App重渲染都被重新创建,输入框的DOM会保持稳定。
修改后的代码:
import axios from 'axios' import { useState, useEffect } from 'react' // 独立的Finder组件,接收props const Finder = ({ newName, handleChange }) => { return( <div> <form> <div> Find country : <input value={newName} onChange={handleChange} /> </div> </form> </div> ) } const App = () => { const [countries, setCountries] = useState([]) const [newName, setNewName] = useState('') // 改成小驼峰命名更符合React规范 useEffect(() => { axios.get('https://restcountries.eu/rest/v2/all') .then(response => { setCountries(response.data) }) }, []) const handleChange = (event) => { setNewName(event.target.value) } return( <div> <p>Meow</p> {/* 传递props给Finder */} <Finder newName={newName} handleChange={handleChange} /> </div> ) } export default App
方法二:直接渲染JSX,不封装内部组件
如果Finder组件的逻辑很简单,没必要单独封装的话,直接把它的JSX内容放到App的return里即可,这样也能避免内部组件重复创建的问题:
import axios from 'axios' import { useState, useEffect } from 'react' const App = () => { const [countries, setCountries] = useState([]) const [newName, setNewName] = useState('') useEffect(() => { axios.get('https://restcountries.eu/rest/v2/all') .then(response => { setCountries(response.data) }) }, []) const handleChange = (event) => { setNewName(event.target.value) } return( <div> <p>Meow</p> {/* 直接渲染输入框,无需封装成内部组件 */} <div> <form> <div> Find country : <input value={newName} onChange={handleChange} /> </div> </form> </div> </div> ) } export default App
补充说明
两种方法的核心都是避免在组件内部重复定义子组件,因为每次父组件重渲染时,内部定义的子组件都会被重新创建,导致DOM树重新生成,输入框自然就失去焦点了。另外顺便提一下,变量名setnewName改成setNewName更符合React的小驼峰命名规范哦~
内容的提问来源于stack exchange,提问作者ilulale
相关产品推荐
相关产品推荐

