React运行时动态创建组件出现重渲染状态丢失,求正确实现方案
问题根因
你当前写法的核心问题是每次App组件重渲染时,都会通过gen_Comp生成一个全新的组件函数实例。React做Diff比对时,会把不同引用的组件函数判定为不同的组件类型,直接卸载旧组件、挂载新组件,旧组件内部的所有状态自然就全部丢失了,该问题和你用JSX还是React.createElement实现无关。
正确实现方案
根据你的业务场景可以选择以下三种方案:
方案1:优先将动态参数转为普通props(最推荐)
不需要额外生成组件工厂,直接把动态的my_spec作为组件的常规props传递,组件定义完全抽到渲染逻辑外部,全局仅初始化一次:
// 组件定义放到App组件外部,引用固定不会变化 const Comp = (props) => { return <h1>{props.my_spec} {props.txt}</h1>; } const App = () => { // 直接传动态参数即可,无需运行时生成组件 return ( <Comp my_spec="Hello" txt="World" /> ); }
该方案性能最优,完全不会出现状态丢失问题,90%以上的常规场景都可以用这个方案解决。
方案2:运行时生成组件时缓存实例
如果你的业务逻辑确实需要基于配置动态生成组件(比如低代码场景根据协议生成组件),需要把生成的组件实例缓存起来,保证重渲染时组件引用不会变化:
import { useMemo } from 'react'; const gen_Comp = (my_spec) => (props) => { return <h1>{my_spec} {props.txt}</h1>; } const App = () => { // 用useMemo缓存生成的组件实例,依赖项不变的情况下不会重新生成 const Comp = useMemo(() => gen_Comp("Hello"), []); return ( <Comp txt="World" /> ); }
如果gen_Comp的入参是动态变化的,需要把对应的参数放到useMemo的依赖数组里,参数变化时重新生成新组件,此时旧状态丢失属于预期行为。
方案3:直接渲染元素而非组件实例
如果不需要动态生成的组件有自己的内部状态,也可以直接返回React元素而非组件函数,绕开组件Diff的判定逻辑:
const gen_Comp_Element = (my_spec, props) => { return <h1>{my_spec} {props.txt}</h1>; } const App = () => { return ( <> {gen_Comp_Element("Hello", {txt: "World"})} </> ); }
内容的提问来源于stack exchange,提问作者Tohmaxxx
相关产品推荐
相关产品推荐

