也是今天突然的回想到了这个问题,然后想通了;。。。
关于前面做低代码时,做远程组件的加载,拿到远程组件后,函数式组件的setState进去,渲染时会崩掉的问题。
原因在于setState是可以接收两种参数的,传入一个函数的话,他会执行后返回函数的执行结果,在去set一个新的状态,这个的话是react的基础问题了。
import React, { useEffect, useState } from "react";
import "./1.0-Component.css";
function Co(props) {
const [count, setCount] = useState(1);
useEffect(() => {
setCount(2);
}, []);
console.log(props, "props");
return (
<p>
{1}
{props?.c}
</p>
);
}
function Demo() {
const [Com, setCom] = useState();
const handleClick = () => {
// 第一种
// setCom(Co)
// 第二种
// setCom(<Co />)
// 第三种
setCom(() => Co);
};
return (
<button onClick={handleClick}>
test
{Com && <Com />}
</button>
);
}
export default Demo;
关键在于就是,我们拿到的组件,其实也就是一个已经经过babel编译过的render函数了,那么直接去set进去,就会执行这个函数,render函数返回的值是什么呢? 是组件节点的虚拟dom的对象,所以此时的state已经是一个虚拟dom的对象了,我们渲染的话直接渲染该对象即可,如果还是以jsx语法去进行渲染的话就会,崩掉,因为渲染的本质就是render方法的执行。
这里的虚拟dom对象的结构
$$typeof: Symbol(react.element)
key: null
props: {}
ref: null
type: ƒ Co(props)
_owner: null
_store: {validated: false}
_self: undefined
_source: {fileName: '/Users/linzai/WebstormProjects/codelearn/src/lesson-1/1.0-Component.jsx', lineNumber: 24, columnNumber: 12}
[[Prototype]]: Object
type属性只有我们自己定义的组件才有这个属性,并且可以通过执行虚拟dom的type方法进行render的,props 也通过方法参数进行一个传递。(这个拓展一下render方法做的事情也就是如何去生成虚拟dom的,emmm其实也只是去处理的keyt,ype,ref,props,还有就是递归的执行children里面的内容,diff的话,也是虚拟dom节点与fiber节点的key与type做对比而已)
第二种的话是set一个jsx的组件进去,但是与set一个函数的区别在于set一个函数对象,他会直接去执行,函数,然后返回,返回的不是组件本身了,而是基于真实dom构建的虚拟dom对象,也就是返回的对象是没有type这个属性的,但是我们去set一个jsx的话,emm他执行的其实是经过babel编辑后的产生的render函数,他们之间是有很大的差别的 。
后面的解决办法的话,我们去用第三种的方式去做一个执行即可,这样返回的也只是组件对应的render函数了,而不是虚拟dom的对象
当然也有其他的解决办法,就是直接set一个组件的话也是ok的,不过会在set的时候就已经执行了render函数了,返回的虚拟对象是可以直接使用的,因为渲染的本质也只是render的执行生成虚拟dom树而已。但是props如何传递呢???,第已反应是给虚拟对象赋值props属性,生成的虚拟dom确实由props这个key,但是是只读的,应该是在对象的可描述属性那一层对props进行重写了,,我觉得可以试试对象合并,这种没试过。
第三种是去执行生成的虚拟dom的type方法,也是ok的,不过这只是基于我们自己的组件才有这个方法。
问题的核心:jsx的本质是一个render函数,setState如果传入一个参数的话会去执行,然后将结果作为新的state(很基础的东西了),渲染的过程本就是render方法的执行,生成虚拟dom,基于新dom树与旧fiber树进行diff(为什么是旧fiber树,因为react实际上会维护两颗fiber树,一颗对应当前渲染的dom树,另一颗旧的就是上次diff完成后的dom树,其实这个理解还是很难的,,,)。崩掉的话是在render执行就g了。
Like
涛神
Like
god