在父组件内定义子组件对React重渲染、挂载/卸载的影响
React 组件重渲染与挂载/卸载问题解析
问题背景
当在父函数组件内部定义子函数组件时,父组件因状态变化触发重渲染,内部的子组件会随之重渲染,还是先卸载再重新挂载?
以提供的代码场景为例:用户在输入框中输入内容时,每次按键后输入框都会失去焦点(React Native中表现为键盘消失)。问题根源被指向Form组件重渲染时Input子函数被重新声明,但需要明确“重新声明”对应的具体组件行为。
代码示例
import { useState } from 'react'; const Form = () => { const [values, setValues] = useState(['', '']); const onChange = (value, index) => { const newValues = [...values]; newValues[index] = value; setValues(newValues); }; const Input = (props) => { return <input type='text' {...props} />; }; return ( <> {values.map((value, index) => ( <Input key={index} value={value} onChange={(e) => onChange(e.target.value, index)} /> ))} <button onClick={() => setValues([...values, ''])}>Add</button> </> ); };
核心解答
每次父组件Form重渲染时,内部的Input函数都会被重新声明——这意味着React会将这个新的Input视为一个完全不同的组件类型。此时React的处理逻辑是:先卸载之前挂载的旧Input组件实例,再挂载新声明的Input组件实例。
正是这个卸载-重新挂载的过程导致了输入框失焦:旧的输入框DOM元素被移除,新的输入框DOM元素被创建,自然丢失了之前的焦点状态。
解决方案
方案1:将子组件移到父组件外部
把Input组件定义在Form组件之外,这样每次Form重渲染时,Input的引用不会改变,React会识别为同一个组件类型,只会触发组件的重渲染(更新props),不会执行卸载和重新挂载操作:
import { useState } from 'react'; const Input = (props) => { return <input type='text' {...props} />; }; const Form = () => { const [values, setValues] = useState(['', '']); const onChange = (value, index) => { const newValues = [...values]; newValues[index] = value; setValues(newValues); }; return ( <> {values.map((value, index) => ( <Input key={index} value={value} onChange={(e) => onChange(e.target.value, index)} /> ))} <button onClick={() => setValues([...values, ''])}>Add</button> </> ); };
方案2:直接调用函数而非作为组件渲染
将Input作为普通函数直接调用,而不是以组件标签的形式渲染。此时Input返回的input元素会被视为父组件渲染输出的一部分,React只会更新元素的props,不会触发组件的卸载/挂载逻辑:
// 保持Input在Form内部定义不变 return ( <> {values.map((value, index) => ( {Input({ key: index, value: value, onChange: (e) => onChange(e.target.value, index) })} ))} <button onClick={() => setValues([...values, ''])}>Add</button> </> );
内容的提问来源于stack exchange,提问作者JustDev
相关产品推荐
相关产品推荐

