当前位置: 首页 > 科技观察

React组件什么时候渲染?_0

时间:2023-03-18 19:42:25 科技观察

今天我们React源码交流群的小伙伴问了一个很有意思的问题。觉得对React运行过程比较了解的同学可以看看。下面这个Demo,点击Parent组件的div触发更新,Son组件会打印childrender吗!?functionSon(){console.log('childrender!');return

Son
;}functionParent(props){const[count,setCount]=React.useState(0);return({setCount(count+1)}}>count:{count}{props.children}
);}functionApp(){return();}constrootEl=document.querySelector("#root");ReactDOM.render(,rootEl);在线演示地址[1]👉向右滑动显示答案:需要满足的条件render不会被React创建,在构建树时,每个组件对应的fiber是通过以下两种逻辑之一创建的:即调用render函数,根据返回的JSX创建一个新的fiber。救助。即当满足一定的条件时,React判断组件在更新前后都没有发生变化,然后复用上一次更新时组件的fiber作为本次更新的fiber。可以看出,当bailout逻辑被命中时,render函数是不会被调用的。因此,Son组件不会打印childrender!这是因为救助逻辑被击中了。什么情况下救助会进入救助逻辑?当同时满足以下四个条件时:1.oldProps===newProps?即本次更新的道具(newProps)不等于上次更新的道具(oldProps)。请注意,这是同余比较。我们知道组件渲染会返回JSX,这是React.createElement的语法糖。所以render的返回结果其实就是React.createElement的执行结果,也就是一个包含props属性的对象。虽然这次更新和上一次更新props中的每个参数都没有变化,但是这次更新是React.createElement的执行结果,是一个全新的props引用,所以oldProps!==newProps。如果我们使用PureComponent或者Memo,在判断是否进入render或者bailout时,不会判断oldProps和newProps是否相等,而是对props中的各个属性进行浅比较。2.上下文没有改变,即上下文的值没有改变。3.workInProgress.type===current.type?更新前后fiber.type是否变化,比如div是否变成了p。4.!includesSomeLane(renderLanes,updateLanes)?当前纤程上是否有更新,如果有,更新的优先级是否与本次整个纤程树调度的优先级一致?如果一致,则进入渲染逻辑。就我们的Demo而言,Parent是整个树中唯一可以触发更新(通过调用setCount)的组件。因此,Parent对应的fiber是唯一满足条件4的fiber。Demo的详细执行逻辑So,在Demo中,Son进入bailout逻辑,必须同时满足以上四个条件。让我们一一看看。条件2,Demo中没有使用context,满足。条件3,更新前后,type为Son对应的函数组件,满足。条件4,Son自身不能触发更新,满足。那么,重点就放在条件1上了,我们详细看一下。在本次更新之初,Fiber树有如下两个fiber:FiberRootNode|RootFiber,其中FiberRootNode是整个应用的根节点,RootFiber是调用ReactDOM.render创建的fiber。首先,RootFiber会进入bailout逻辑,所以返回的Appfiber和更新前一样。FiberRootNode|RootFiber|Appfiber因为Appfiber是RootFiber通过bailout逻辑返回的,所以对于Appfiber,oldProps===newProps。而剩下的3个救市条件也都满足了。因此,Appfiber也会按照bailout逻辑返回Parentfiber。FiberRootNode|RootFiber|Appfiber|Parentfiber由于更新是由Parentfiber触发的,不满足条件4,会遵循render的逻辑。接下来是关键,如果render返回的Son是下面的形式:会被编译成React.createElement(Son,null),执行完返回给JSX。OldProps!==newProps由于props引用的变化。将遵循渲染逻辑。但是在Demo中,Son有如下形式:{props.children}其中,props.children是Son对应的JSX,这里的props是Appfiber执行bailout逻辑后返回的。所以Son对应的JSX与上次更新一致,JSX中保存的props也一致,满足条件1。可见Son满足bailout的所有条件,所以不会渲染。总结当你理解了这4个条件,你就会对React组件更新有一个全新的认识。不得不说React真的好难,工友们流下了失望的眼泪。