React/Preact中按状态切换同类型FormInput组件props异常问题求助
问题根因
这个问题本质是React/Preact的虚拟DOM Diff规则和组件内部代码疏漏共同导致的,核心原因如下:
1. 虚拟DOM的默认复用规则
当同层级的两个节点类型完全相同时,React/Preact会默认复用同一个组件实例,仅更新传入的props,而不会销毁旧实例再创建新实例。
你最初的三元表达式两端都是<FormInput>组件,切换单选按钮时框架会判定为同一个组件需要更新props,不会重建实例。
2. 组件内部的依赖疏漏
你写的FormInput组件中,onInput的useCallback依赖数组为空,但回调内部用到了props传入的name变量:
const onInput = useCallback((e: any) => { handleValueChange(name, e.target.value,); }, []); // 这里漏加了name、handleValueChange依赖
因为依赖数组为空,这个回调函数只会在组件第一次初始化时创建一次,永远绑定第一次渲染时拿到的name值,哪怕后续props更新了,回调也不会刷新,就会出现「渲染内容正常但逻辑上的props还是旧值」的现象。
为什么加空标签后问题消失
你给其中一个<FormInput>外层包裹了空标签(Fragment)后,三元表达式两端的节点类型变成了「Fragment」和「FormInput」,框架Diff时发现类型不一致,会直接销毁旧节点,重新创建新的组件实例,旧的错误回调也会被销毁,相当于歪打正着规避了复用导致的问题。
正确修复方案
不需要额外包裹空标签,按以下两步调整即可:
- 补全
useCallback的依赖项,所有回调内部用到的外部变量都要加到依赖数组中:
const onInput = useCallback((e: any) => { handleValueChange(name, e.target.value); }, [name, handleValueChange]); // 补全依赖
- 给两个切换渲染的
<FormInput>加上唯一的key属性,明确告诉框架这是两个不同的业务组件,不要复用:
{ this.state.radio === true ? <FormInput key="keyword" id="keyword" name="keyword" required={true}>Keyword</FormInput> : <FormInput key="url" id="url" name="url" required={true} placeholder="https://" pattern={'https://.*'} >URL</FormInput> }
内容的提问来源于stack exchange,提问作者Julien
相关产品推荐
相关产品推荐

