当前位置: 首页 > news >正文

专业分销电商平台seo排名查询软件

专业分销电商平台,seo排名查询软件,网站开发最新架构,wordpress 2个菜单做中英文reconcileChildren 1 #xff09;概述 在更新了一个节点之后#xff0c;拿到它的props.children要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象要根据 props.children 来生成 fiber 子树#xff0c;然后判断 fiber 对象它是否是可以复用的 因为我…reconcileChildren 1 概述 在更新了一个节点之后拿到它的props.children要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象要根据 props.children 来生成 fiber 子树然后判断 fiber 对象它是否是可以复用的 因为我们在第一次渲染的时候就已经渲染了整个 fiber 子树再有一个更新进来之后state 变化可能会导致一些子节点产生一个新的变化可能就不能复用之前的 fiber 节点了它里面的很多东西都变得不一样大部分情况下所有 fiber 节点都是可以可以重复利用的这个时候我们根据什么进行判断是这里面的一个非常重要的一个点 在这里就会拿出react当中的非常重要的key列表根据key来优化 2 源码 在 packages/react-reconciler/src/ReactFiberBeginWork.js#L137 中 export function reconcileChildren(current: Fiber | null,workInProgress: Fiber,nextChildren: any,renderExpirationTime: ExpirationTime, ) {if (current null) {// If this is a fresh new component that hasnt been rendered yet, we// wont update its child set by applying minimal side-effects. Instead,// we will add them all to the child before it gets rendered. That means// we can optimize this reconciliation pass by not tracking side-effects.workInProgress.child mountChildFibers(workInProgress,null,nextChildren,renderExpirationTime,);} else {// If the current child is the same as the work in progress, it means that// we havent yet started any work on these children. Therefore, we use// the clone algorithm to create a copy of all the current children.// If we had any progressed work already, that is invalid at this point so// lets throw it out.workInProgress.child reconcileChildFibers(workInProgress,current.child,nextChildren,renderExpirationTime,);} }可见根据 current 是否为 null 调用两个方法: mountChildFibers, reconcileChildFibers 两个方法的区别在第二个参数在前者方法中传递的是 null, 因为 第一次渲染不存在 current.child因为第一次渲染的时候都是父亲节点先渲染子节点后渲染只有在后续的渲染过程当中已经过第一次渲染了我们的父节点这个时候才有一个子节点存在所以这是一个区别在 react-reconciler/src/ReactFiberBeginWork.js 中 的 reconcileChildren 调用这个 reconcileChildFibers 看一下这两个方法它们来自于 ReactChildFiber.jsexport const reconcileChildFibers ChildReconciler(true); export const mountChildFibers ChildReconciler(false);可见上述两个方法的区别是 参数的 true 和 false 这个参数的意思是: 表示是否要跟踪副作用 进入 ChildReconciler这个方法 1k 多行这里不去全部摘抄用到哪里逐个分析 整体框架 // 参数 shouldTrackSideEffects 表示是否要跟踪副作用 function ChildReconciler(shouldTrackSideEffects) {// ... 跳过很多代码// This API will tag the children with the side-effect of the reconciliation// itself. They will be added to the side-effect list as we pass through the// children and the parent.function reconcileChildFibers(returnFiber: Fiber,currentFirstChild: Fiber | null,newChild: any,expirationTime: ExpirationTime,): Fiber | null {// 省略很多代码// Remaining cases are all treated as empty.return deleteRemainingChildren(returnFiber, currentFirstChild);}return reconcileChildFibers; }在 ChildReconciler 方法的最后, return reconcileChildFibers;先看下这个方法 // This API will tag the children with the side-effect of the reconciliation // itself. They will be added to the side-effect list as we pass through the // children and the parent. function reconcileChildFibers(returnFiber: Fiber,currentFirstChild: Fiber | null,newChild: any,expirationTime: ExpirationTime, ): Fiber | null {// This function is not recursive.// If the top level item is an array, we treat it as a set of children,// not as a fragment. Nested arrays on the other hand will be treated as// fragment nodes. Recursion happens at the normal flow.// Handle top level unkeyed fragments as if they were arrays.// This leads to an ambiguity between {[...]}/ and .../.// We treat the ambiguous cases above the same.// newChild 是计算出来的 新children// 这个节点是一个 top level 的节点因为 / 这种类型会匹配 REACT_FRAGMENT_TYPE// 符合以下就是没有key的 topLevel节点const isUnkeyedTopLevelFragment typeof newChild object newChild ! null newChild.type REACT_FRAGMENT_TYPE newChild.key null;// 如果匹配了那么 Fragment 是没有任何的操作更新的, 本身并没有什么实际的意义// 如果匹配了则将newChild赋值if (isUnkeyedTopLevelFragment) {newChild newChild.props.children;}// Handle object typesconst isObject typeof newChild object newChild ! null;// 如果是对象说明有下面两种情况// 下面两种方法调用相似都是基于 placeSingleChild 传递不同参数// 一个是 reconcileSingleElement// 另一个是 reconcileSinglePortalif (isObject) {switch (newChild.$$typeof) {// 匹配 REACT_ELEMENT是通过 React.createElement 产生的case REACT_ELEMENT_TYPE:return placeSingleChild(reconcileSingleElement(returnFiber,currentFirstChild,newChild,expirationTime,),);// 匹配 REACT_PORTAL, 是通过 ReactDOM.createPortalcase REACT_PORTAL_TYPE:return placeSingleChild(reconcileSinglePortal(returnFiber,currentFirstChild,newChild,expirationTime,),);}}// 匹配到 string 和 number 类就是 text类型的Nodeif (typeof newChild string || typeof newChild number) {return placeSingleChild(reconcileSingleTextNode(returnFiber,currentFirstChild, newChild,expirationTime,),);}// 匹配到数组if (isArray(newChild)) {return reconcileChildrenArray(returnFiber,currentFirstChild,newChild,expirationTime,);}// 匹配到可迭代的对象if (getIteratorFn(newChild)) {return reconcileChildrenIterator(returnFiber,currentFirstChild,newChild,expirationTime,);}// 以上都没有匹配但仍然是对象则 throw errorif (isObject) {throwOnInvalidObjectType(returnFiber, newChild);}// 忽略 DEVif (__DEV__) {if (typeof newChild function) {warnOnFunctionType();}}// 匹配到 undefined 的对象if (typeof newChild undefined !isUnkeyedTopLevelFragment) {// If the new child is undefined, and the return fiber is a composite// component, throw an error. If Fiber return types are disabled,// we already threw above.switch (returnFiber.tag) {// 匹配到 ClassComponent 忽略case ClassComponent: {if (__DEV__) {const instance returnFiber.stateNode;if (instance.render._isMockFunction) {// We allow auto-mocks to proceed as if theyre returning null.break;}}}// Intentionally fall through to the next case, which handles both// functions and classes// eslint-disable-next-lined no-fallthrough// 匹配到 FunctionComponent 提醒case FunctionComponent: {const Component returnFiber.type;invariant(false,%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.,Component.displayName || Component.name || Component,);}}}// Remaining cases are all treated as empty.// 以上都不符合则 是 null, 删除现有所有 children// 新的 props.children 都是 null, 老的 props 节点都应该被删除return deleteRemainingChildren(returnFiber, currentFirstChild); }接下来看不同节点的更新 reconcileSingleElement // 从当前已有的所有子节点中找到一个可以复用新的子节点的Fiber对象 // 复用它之后把剩下兄弟节点全部删掉 function reconcileSingleElement(returnFiber: Fiber,currentFirstChild: Fiber | null, // 是当前已有的fiber节点初次渲染没有后续渲染后很可能存在element: ReactElement,expirationTime: ExpirationTime, ): Fiber {// 获取 key 和 childconst key element.key;let child currentFirstChild;// child 存在while (child ! null) {// TODO: If key null and child.key null, then this only applies to// the first item in the list.if (child.key key) {// 注意这个判断if (child.tag Fragment? element.type REACT_FRAGMENT_TYPE // 是否是 frament: child.elementType element.type // 新老 element type) {// 删除 已存在当前节点的兄弟节点// 为何要删除兄弟节点因为我们这次渲染只有一个节点老的节点有兄弟节点新的节点只有一个删除之deleteRemainingChildren(returnFiber, child.sibling);const existing useFiber(child,element.type REACT_FRAGMENT_TYPE? element.props.children: element.props,expirationTime,);// 挂载属性existing.ref coerceRef(returnFiber, child, element);existing.return returnFiber;if (__DEV__) {existing._debugSource element._source;existing._debugOwner element._owner;}// 找到可复用节点直接returnreturn existing;} else {// 条件不符合删除节点并退出 deleteRemainingChildren(returnFiber, child);break;}} else {// key 不同则删除deleteChild(returnFiber, child);}// 当前兄弟节点 等于 child 再次进入while循环child child.sibling;}// 创建新的节点, 基于各种不同的类型调用不同的创建 Fiber的方式if (element.type REACT_FRAGMENT_TYPE) {const created createFiberFromFragment(element.props.children, // 注意这个参数returnFiber.mode,expirationTime,element.key,);created.return returnFiber;return created;} else {const created createFiberFromElement(element,returnFiber.mode,expirationTime,);created.ref coerceRef(returnFiber, currentFirstChild, element);created.return returnFiber;return created;} }进入 createFiberFromFragmentexport function createFiberFromFragment(elements: ReactFragment,mode: TypeOfMode,expirationTime: ExpirationTime,key: null | string, ): Fiber {const fiber createFiber(Fragment, elements, key, mode);fiber.expirationTime expirationTime;return fiber; }// This is a constructor function, rather than a POJO constructor, still // please ensure we do the following: // 1) Nobody should add any instance methods on this. Instance methods can be // more difficult to predict when they get optimized and they are almost // never inlined properly in static compilers. // 2) Nobody should rely on instanceof Fiber for type testing. We should // always know when it is a fiber. // 3) We might want to experiment with using numeric keys since they are easier // to optimize in a non-JIT environment. // 4) We can easily go from a constructor to a createFiber object literal if that // is faster. // 5) It should be easy to port this to a C struct and keep a C implementation // compatible. const createFiber function(tag: WorkTag,pendingProps: mixed, // 对于 fragment来说props只有children, 直接把children作为propskey: null | string,mode: TypeOfMode, ): Fiber {// $FlowFixMe: the shapes are exact here but Flow doesnt like constructorsreturn new FiberNode(tag, pendingProps, key, mode); };以上的 fragment 可以在 ReactFiberBeginWork.js 中的 updateFragment 方法中找到验证function updateFragment(current: Fiber | null,workInProgress: Fiber,renderExpirationTime: ExpirationTime, ) {// 看这里直接通过 .pendingProps 而非 props.children 获取参考上述 createFiber 写明原因const nextChildren workInProgress.pendingProps;reconcileChildren(current,workInProgress,nextChildren,renderExpirationTime,);return workInProgress.child; }进入 createFiberFromElementexport function createFiberFromElement(element: ReactElement,mode: TypeOfMode,expirationTime: ExpirationTime, ): Fiber {let owner null;if (__DEV__) {owner element._owner;}// 获取各类属性const type element.type;const key element.key;const pendingProps element.props;// 创建 Fiberconst fiber createFiberFromTypeAndProps(type,key,pendingProps,owner,mode,expirationTime,);if (__DEV__) {fiber._debugSource element._source;fiber._debugOwner element._owner;}return fiber; }进入 createFiberFromTypeAndProps// 这个方法比较复杂要判断不同的 type 给 fiber 对象增加 不同的 tag // 主要是去匹配 fiberTag export function createFiberFromTypeAndProps(type: any, // React$ElementTypekey: null | string,pendingProps: any,owner: null | Fiber,mode: TypeOfMode,expirationTime: ExpirationTime, ): Fiber {let fiber;// 组件tag未知时的初始化配置 未指定状态let fiberTag IndeterminateComponent;// The resolved type is set if we know what the final type will be. I.e. its not lazy.let resolvedType type;// 根据不同类型来处理 fiberTagif (typeof type function) {// 判断是否有 constructor 方法/*function shouldConstruct(Component: Function) {const prototype Component.prototype;// 注意这里 isReactComponent 是一个 {}return !!(prototype prototype.isReactComponent);}*/if (shouldConstruct(type)) {fiberTag ClassComponent;}} else if (typeof type string) {fiberTag HostComponent;} else {getTag: switch (type) {case REACT_FRAGMENT_TYPE:return createFiberFromFragment(pendingProps.children,mode,expirationTime,key,);case REACT_CONCURRENT_MODE_TYPE:return createFiberFromMode(pendingProps,mode | ConcurrentMode | StrictMode,expirationTime,key,);case REACT_STRICT_MODE_TYPE:return createFiberFromMode(pendingProps,mode | StrictMode,expirationTime,key,);case REACT_PROFILER_TYPE:return createFiberFromProfiler(pendingProps, mode, expirationTime, key);case REACT_SUSPENSE_TYPE:return createFiberFromSuspense(pendingProps, mode, expirationTime, key);default: {if (typeof type object type ! null) {switch (type.$$typeof) {case REACT_PROVIDER_TYPE:fiberTag ContextProvider;break getTag;case REACT_CONTEXT_TYPE:// This is a consumerfiberTag ContextConsumer;break getTag;case REACT_FORWARD_REF_TYPE:fiberTag ForwardRef;break getTag;case REACT_MEMO_TYPE:fiberTag MemoComponent;break getTag;case REACT_LAZY_TYPE:fiberTag LazyComponent;resolvedType null;break getTag;}}let info ;if (__DEV__) {if (type undefined ||(typeof type object type ! null Object.keys(type).length 0)) {info You likely forgot to export your component from the file its defined in, or you might have mixed up default and named imports.;}const ownerName owner ? getComponentName(owner.type) : null;if (ownerName) {info \n\nCheck the render method of ownerName .;}}invariant(false,Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s,type null ? type : typeof type,info,);}}}// 最终创建 Fiberfiber createFiber(fiberTag, pendingProps, key, mode);fiber.elementType type;fiber.type resolvedType;fiber.expirationTime expirationTime;return fiber; }以上reconcileSingleElement 就完了 进入 reconcileSingleTextNode function reconcileSingleTextNode(returnFiber: Fiber,currentFirstChild: Fiber | null,textContent: string,expirationTime: ExpirationTime, ): Fiber {// Theres no need to check for keys on text nodes since we dont have a// way to define them.// 处理 原生 标签if (currentFirstChild ! null currentFirstChild.tag HostText) {// We already have an existing node so lets just update it and delete// the rest.// 删除兄弟节点新节点只是一个纯的文本节点deleteRemainingChildren(returnFiber, currentFirstChild.sibling);// 基于 useFiber 复用当前节点const existing useFiber(currentFirstChild, textContent, expirationTime);existing.return returnFiber;return existing;}// The existing first child is not a text node so we need to create one// and delete the existing ones.deleteRemainingChildren(returnFiber, currentFirstChild);const created createFiberFromText(textContent,returnFiber.mode,expirationTime,);created.return returnFiber;return created; }这个流程就比较简单了 现在我们主要看下 deleteRemainingChildren 这个api function deleteRemainingChildren(returnFiber: Fiber, // 当前正在更新的节点currentFirstChild: Fiber | null, // 子节点 ): null {// 这是第一次渲染的时候没有子节点// 直接 returnif (!shouldTrackSideEffects) {// Noop.return null;}// TODO: For the shouldClone case, this could be micro-optimized a bit by// assuming that after the first child weve already added everything.// 一个个的删除let childToDelete currentFirstChild;while (childToDelete ! null) {deleteChild(returnFiber, childToDelete);childToDelete childToDelete.sibling;}return null; }进入 deleteChild// 可以看到这里没有实施删除的操作只是改变了节点上的 effectTag // 这里我们只更新 Fiber Tree, 如果真的要 delete 就会影响到 dom节点 // 所以删除的流程不在这里做只有在下个阶段也就是 commit 阶段来做 // 就是把Fiber Tree 需要更新的流程都过一遍之后把整个需要更新的属性 // 通过 firstEffectlastEffect 这种链条最终链到根节点上面 // 最终要执行更新 只需要在 commit 阶段拿到 根节点上面的 这种链条把每个节点去执行即可 // 在处理更新的时候任务是可以中断的但是在 commit 阶段任务是不可中断的 function deleteChild(returnFiber: Fiber, childToDelete: Fiber): void {if (!shouldTrackSideEffects) {// Noop.return;}// Deletions are added in reversed order so we add it to the front.// At this point, the return fibers effect list is empty except for// deletions, so we can just append the deletion to the list. The remaining// effects arent added until the complete phase. Once we implement// resuming, this may not be true.const last returnFiber.lastEffect;// 存在 lastif (last ! null) {last.nextEffect childToDelete;returnFiber.lastEffect childToDelete;} else {// 不存在 lastreturnFiber.firstEffect returnFiber.lastEffect childToDelete;}childToDelete.nextEffect null; // 已经是要删除的节点上面的其他副作用都是没有任何意义的// effectTag 就是告诉后续的 commit 阶段对于这个节点需要执行什么操作可以看到这里是删除childToDelete.effectTag Deletion; // 只需要设置这个即可 }reconcileChildrenArray 和 reconcileChildrenIterator 这两个api比较复杂先跳过 其他的 API 都是比较简单了
http://www.dnsts.com.cn/news/50141.html

相关文章:

  • 公司建设网站产生哪些费用北京哪个公司做网站
  • 上海网站建设排名公司福州php做网站
  • 织梦网站地图个人网页制作总结
  • 沈阳市网站建设公司wordpress 帝国 seo
  • 有哪些制作网站的公司吗房地产管理软件
  • 北京网站设计公司飞沐驻马店市住房和城乡建设局网站
  • 什么免费推广网站好江苏建设人才无纸化考核网站
  • 做网站如何挂支付系统手机在线做ppt的网站有哪些问题
  • 网站ui怎么做的安阳包装设计
  • 网站说建设中设计师必备网站
  • 哪个网站做的比较好万家建设有限公司网站
  • 网上做结婚照的网站安装wordpress提示500错误
  • 网站建设经营范围怎么写网站开发要用什么工具软件
  • 网站建设教程这篇苏州久远网络淮安公司企业网站建设
  • 站内站怎么搭建wordpress装在xampp
  • 企业网站开发外包合同公司推广哪个平台好
  • 网站开发与管理微网站建设教程视频
  • 那个网站卖做防水的烤枪邀请注册推广赚钱
  • 海口网站公司如何做好专业类网站
  • 网站开发费怎样入账淄博网站建设团队
  • 长沙做信息seo网站软件开发外包商业模式
  • 网站开发流程进度表用vue做网站
  • 怎样电脑登录网站乐平网站
  • pageadmin仿站教程学物联网工程后悔死了
  • 网站建设营业执照wordpress链接跳转错误
  • 开通公司网站怎么做分录哈尔滨建站模板
  • 网站搭建详细教程discuz模板下载
  • 广州优化网站推广网站的虚拟人怎么做的
  • 网站的ftp怎么登陆有哪些企业官网做得比较好
  • 外链网站推荐几个巴中做网站公司