React内部子组件输入失焦问题求助
输入框失焦问题原因及解决方法
问题原因
你把表单定义成组件内部的函数,每次主组件状态更新时,这个内部函数都会被重新创建。React会把它识别成一个全新的组件,随即卸载旧的表单组件、挂载新的实例。这就导致你输入第一个字符触发状态更新后,旧输入框被销毁,焦点自然丢失——哪怕加了autoFocus也没用,因为新组件挂载时的焦点触发时机和输入动作不匹配。
解决办法
针对你的情况(10个表单不想全部塞进主render),有三种可行方案:
1. 把表单组件抽成外部独立组件
把每个表单组件移到主组件外面作为单独的函数组件,这样每次主组件重渲染时,表单组件的引用不会改变,React就不会重复执行卸载和挂载操作,输入框焦点就能稳定保持。
// 外部独立定义表单组件 const BoatForm = ({ value, onChange }) => ( <div> <label>Number of Boats</label> <input type="number" value={value} onChange={onChange} /> </div> ); const HouseForm = ({ value, onChange }) => ( <div> <label>Number of Houses</label> <input type="number" value={value} onChange={onChange} /> </div> ); // 主组件 const MainComponent = () => { const [boatCount, setBoatCount] = useState(0); const [houseCount, setHouseCount] = useState(0); return ( <div> <BoatForm value={boatCount} onChange={(e) => setBoatCount(e.target.value)} /> <HouseForm value={houseCount} onChange={(e) => setHouseCount(e.target.value)} /> {/* 其他8个表单组件同理引入 */} </div> ); };
2. 用useMemo缓存内部组件函数
如果不想把组件移出去,用useMemo缓存内部组件的引用,确保每次重渲染时组件的身份不变。注意要设置正确的依赖项(如果组件不需要依赖主组件的状态/ props,依赖数组留空即可)。
const MainComponent = () => { const [boatCount, setBoatCount] = useState(0); const [houseCount, setHouseCount] = useState(0); // 缓存BoatForm组件引用 const BoatForm = useMemo(() => { return ({ value, onChange }) => ( <div> <label>Number of Boats</label> <input type="number" value={value} onChange={onChange} /> </div> ); }, []); // 缓存HouseForm组件引用 const HouseForm = useMemo(() => { return ({ value, onChange }) => ( <div> <label>Number of Houses</label> <input type="number" value={value} onChange={onChange} /> </div> ); }, []); return ( <div> <BoatForm value={boatCount} onChange={(e) => setBoatCount(e.target.value)} /> <HouseForm value={houseCount} onChange={(e) => setHouseCount(e.target.value)} /> </div> ); };
3. 将内部组件改成普通渲染函数
把原本的内部“组件”改成普通的渲染函数,直接返回JSX,在主组件里直接调用函数(而不是用组件标签<Component />)。这样相当于把JSX直接嵌入主组件的渲染结果,不会被当作独立组件处理,也就不会有卸载挂载的问题。
const MainComponent = () => { const [boatCount, setBoatCount] = useState(0); const [houseCount, setHouseCount] = useState(0); // 普通渲染函数,不是组件 const renderBoatForm = () => ( <div> <label>Number of Boats</label> <input type="number" value={boatCount} onChange={(e) => setBoatCount(e.target.value)} /> </div> ); const renderHouseForm = () => ( <div> <label>Number of Houses</label> <input type="number" value={houseCount} onChange={(e) => setHouseCount(e.target.value)} /> </div> ); return ( <div> {renderBoatForm()} {renderHouseForm()} {/* 其他表单的渲染函数调用 */} </div> ); };
内容的提问来源于stack exchange,提问作者sfhasfasf
相关产品推荐
相关产品推荐

