DOMComponent完成,而setState后,触发到DOM的更新入口是receiveComponent,源码在src/renderers/dom/shared/ReactDOMComponent.js...key是由组件的key生成的,当我们没有指定key的时候,它是这样: 当我们设置key的时候,它是这样: 它的生成函数位于src/shared/utils/traverseAllChildren.js...它完全是根据相同的key来diff,没设置key的话,其实是通过数组下标来进行(源码位于src/renderers/shared/stack/reconciler/ReactChildReconciler.js...,这个条件是必然的,因为在之前reconcile的时候我们就已经把prevChild更新为nextChild了,除非nextChild是全新节点或者删除节点的情况。...这里所有的操作均会被推到队列里面去,最终通过processQueue来执行,它的源码位于src/renderers/dom/client/utils/DOMChildrenOperations.js:
processChildContext(context) ); } else { ... } }, // shouldUpdateReactComponent.js...children, flattenSingleChildIntoContext, result); return result; } // traverseAllChildren.js...= nextChildren[name]; if (prevChild === nextChild) { ------------------------------------...= nextChildren[name]; if (prevChild === nextChild) { ------------------------------------...= nextChildren[name]; if (prevChild === nextChild) { ------------------------------------
minimum-scale=1.0,user-scalable=no,target-densitydpi=medium-dpi,viewport-fit=cover" /> Vue3.js.../dist/vue.global.js"> Vue3源码视频讲解:进入学习源码解读关于Vue3中数据发生变更,最终影响到页面发生变化的过程,我们本篇文章只对componentEffect...(new-b)存不存在,通过newIndexToOldIndexMap发现nextChild存在,并且在old里面的索引值为2,j--,此时j为-1;i--,i为1;第二次循环,判断当前nextChild...第三次循环,判断当前nextChild(new-d)存不存在,通过newIndexToOldIndexMap发现nextChild的索引值为4,表示存在,则调用move;i--,i为-1;改变后c1为'
cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) if (nextChild.key !...= null) { if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) { warn( `Duplicate keys...found during update:`, JSON.stringify(nextChild.key), `Make sure keys are unique.`...) } keyToNewIndexMap.set(nextChild.key, i) } } } let j = 0 // 记录即将 patch 的 新 Vnode...== increasingNewIndexSequence[j]) { move(nextChild, container, anchor, MoveType.REORDER) } else
紧随其后的是kivi.js,在cito.js的基出提出两项优化方案,使用key实现移动追踪及基于key的编辑长度距离算法应用(算法复杂度 为O(n^2))。...但这样的diff算法太过复杂了,于是后来者snabbdom将kivi.js进行简化,去掉编辑长度距离算法,调整两端比较算法。速度略有损失,但可读性大大提高。...nextChild.props.isStatic && curChild.receiveProps(nextChild.props, transaction); curChild...shouldUpdate && nextChild => insert this...._renderedChildren[name] = nextChild; // 渲染下个节点 var nextMarkup = nextChild.mountComponent
本文特别福利,赠送JS新书,详情查看文末~ 希望本篇文章能帮你加深对 Vue 的理解,能信誓旦旦地说自己熟练Vue2/3。 内容混杂用法 + 原理 + 使用小心得,建议收藏,慢慢看。.../useMousePosition' const {x, y} = useMousePosition() } // useMousePosition.js import { ref...cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) if (nextChild.key !...= null) { if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) { warn( `...keys are unique.` ) } keyToNewIndexMap.set(nextChild.key, i) } }
速查: ResourceOwner是多层结构,每次批量释放时,只释放自己同层的资源,不释放父节点资源(同层指针child->nextchild)。...| | v {parent = 0x1996c58, firstchild = 0x0, nextchild...| ^ | | v | {parent = 0x0, firstchild = 0x198a520, nextchild...递归,遍历当前owner同一层的所有owner,按child->nextchild来找;注意,不会释放parent的资源!...= NULL; child = child->nextchild) ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel
cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) patch( c1[i], nextChild...cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) if (nextChild.key !...= null) { if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) { warn( `Duplicate...keys found during update:`, JSON.stringify(nextChild.key), `Make sure keys are unique...== increasingNewIndexSequence[j]) { move(nextChild, container, anchor, MoveType.REORDER)
/useMousePosition' const {x, y} = useMousePosition() } // useMousePosition.js import { ref...cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) if (nextChild.key !...= null) { if (__DEV__ && keyToNewIndexMap.has(nextChild.key)) { warn( `...keys are unique.` ) } keyToNewIndexMap.set(nextChild.key, i) } }...== increasingNewIndexSequence[j]) { move(nextChild, container, anchor, MoveType.REORDER)
name)) { continue; } var prevChild = prevChildren && prevChildren[name]; var nextChild...= nextChildren[name]; if (prevChild === nextChild) { // 同一个引用,说明是使用的同一个component,所以我们需要做移动的操作..._mountChildAtIndex( nextChild, mountImages[nextMountIndex], lastPlacedNode...} // 更新nextIndex nextIndex++; lastPlacedNode = ReactReconciler.getHostNode(nextChild
简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。...dom是昂贵的,昂贵的一方面在dom本身的重量,dom节点在js里的描述是个非常复杂属性很多原型很长的超级对象,另一方面是浏览器渲染进程和js进程是独立分离的,操作dom时的通信和浏览器本身需要重绘的时耗都是很高的...const s2 = i const keyToNewIndexMap = new Map() for (i = s2; i <= e2; i++) { const nextChild...= c2[i] if (nextChild.key !...== null) { keyToNewIndexMap.set(nextChild.key, i) } } } 接下来 for (i = s1; i
int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View nextChild...= mChildren[childIndex]; final float currentZ = nextChild.getZ(); // insert...-; } // 将当前遍历的组件插入到指定索引位置上 mPreSortedChildren.add(insertIndex, nextChild...= mChildren[childIndex]; final float currentZ = nextChild.getZ(); // insert...= mChildren[childIndex]; final float currentZ = nextChild.getZ(); // insert
MOVE_EXISTING:旧集合中有新组件类型,且 element 是可更新的类型,这种情况下 prevChild = nextChild ,这时候就需要做移动操作,可以复⽤以前的 DOM 节点。...diff 逻辑概括 ⾸先对新集合的节点进⾏循环遍历, for (name in nextChildren) ,通过唯⼀ key 可以判断新⽼集合中是否存在相同的节点, if (prevChild === nextChild...= nextChildren[name]; if (prevChild === nextChild) { // 同⼀个引⽤,说明是使⽤的同⼀个component,所以我们需要做移动的操作..._mountChildAtIndex( nextChild, mountImages[nextMountIndex], lastPlacedNode...nextMountIndex++; } nextIndex++; lastPlacedNode = ReactReconciler.getHostNode(nextChild
❞ 准备工作 我们先使用最新版create-react-app,在example/目录下创建一个demo项目: npx create-react-app demo 跑起来后,将index.js替换如下.../App'; ReactDOM.render(, document.getElementById('root')); 在根目录补充react.js和reactDom.js,其中reactDom.js...let i = 0; i < nextChildren.length; i++) { const prevChild = prevChildren[i]; const nextChild...]; const prevComponent = this.childComponents[i]; const nextComponent = instantiate(nextChild...) { // 相同类型的元素,可以直接更新 prevComponent.receive(nextChild); } else {
那这个时候我们也不用DOM了,而是自己去定义个js对象,对象中的key:value呢就包括我们属性名与属性值,每个js对象都对应一个DOM节点。...到这里,相信机智的你已经猜到了,这个我们自己定义的js对象就是传说中的屋子,哦,不对,是传说中的VDOM。 最近刚又看完《奇友》,台词里的《传说中的屋子》实在是太洗脑了。...const s1 = i; const s2 = i; const keyToNewIndexMap = new Map(); for (i = s2; i <= e2; i++) { const nextChild...= c2[i]; keyToNewIndexMap.set(nextChild.key, i); } 学过React VDOM DIFF的可以再来思考一个问题,React中也用到了Map,只不过是把...[i] === 0) { mountElement(nextChild.key); } else { // 可能move } } 通过上面的代码,相信大家对mountElement
newLength) let i for (i = 0; i < commonLength; i++) { /* 依次遍历新老vnode进行patch */ const nextChild...cloneIfMounted(c2[i] as VNode) : normalizeVNode(c2[i])) patch( c1[i], nextChild...number> = new Map() /* 把没有比较过的新的vnode节点,通过map保存 */ for (i = s2; i <= e2; i++) { if (nextChild.key...= null) { keyToNewIndexMap.set(nextChild.key, i) } } let j let patched...== increasingNewIndexSequence[j]) { /*如果没有在长*/ /* 需要移动的vnode */ move(nextChild
1.虚拟dom 原生的JS DOM操作非常消耗性能,而React把真实原生JS DOM转换成了JavaScript对象。...ConardLi 苹果 橘子 在React可能存储为这样的JS.../span> 苹果 橘子 将此JSX元素打印出来,证实虚拟DOM本质就是js...新集合的某个类型组件或元素节点存在旧集合里,且 element 是可更新的类型,generateComponent-Children 已调用receiveComponent,这种情况下 prevChild=nextChild...key的具体执行过程 首先,对新集合中的节点进行循环遍历 for (name in nextChildren),通过唯一的 key 判断新旧集合中是否存在相同的节点 if (prevChild === nextChild
render 函数; 3.watcher: 就是执行1.2.3; 4.patch:就是执行 1.2.4 3.AST 和 VNode 的异同 1.都是 JSON 对象; 2.AST 是HTML,JS...VNode 方法一: // 利用createDocumentFragment()创建虚拟 dom 片段 // 节点对象包含dom所有属性和方法 // html // js...console.log(fragment) element.appendChild(fragment); // 将打包好的文档片段插入ul节点,只做了一次操作,时间快,性能好 方法二: // 用 JS...= nextChildren[name] if (prevChild === nextChild) { // 同一个引用,说明是使用的同一个component,所以我们需要做移动的操作...state 更新,当执行 setState() 时,会将需要更新的 state 浅合并后,根据变量 isBatchingUpdates(默认为 false)判断是直接更新还是放入状态队列; 2.通过js
领取专属 10元无门槛券
手把手带您无忧上云