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

学校网站建设特色学校网站建设责任书

学校网站建设特色,学校网站建设责任书,网站建设与维护试卷论文,如何做网站对话框NewContext 1 #xff09;概述 新的 context API 是一个组件化的使用方式 它就跟写其他的组件一样#xff0c;像写jsx#xff0c;通过标签的这种方式来赋值一些props还有去给子节点去拿到这个 conntext 的属性 context的提供方和订阅方都是独立的 在什么地方想要用到这个 c…NewContext 1 概述 新的 context API 是一个组件化的使用方式 它就跟写其他的组件一样像写jsx通过标签的这种方式来赋值一些props还有去给子节点去拿到这个 conntext 的属性 context的提供方和订阅方都是独立的 在什么地方想要用到这个 context就去声明式的写这个 consumer 就可以了而不需要说在这个子树的渲染过程当中都需要处于这个context的一个环境下面 没有什么附带的性能影响主要关注源码中的 updateContextProvider 和 updateContextConsumer 它们就是通过 createContext 返回的两个组件就是provider和consumer, 它们是一个组件的类型所以它们会有特定的组件的更新方式 而新的context-api都在 ReactFiberNewContext.js 中 它提供的主要核心的两个api就是 pushProvider 以及 popProvider 2 源码 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L1352 function updateContextProvider(current: Fiber | null,workInProgress: Fiber,renderExpirationTime: ExpirationTime, ) {// 在这个更新的过程中去获取了 workingprogress点type// 这个type就是我们通过createcontext返回的那个provider对象// 这个对象上面会有一个属性指向 consumer 那个typeconst providerType: ReactProviderTypeany workInProgress.type; // 这里获得的就是 provider 组件const context: ReactContextany providerType._context; // 这里获得的 context 就是 consumer// 拿到前后两个 propsconst newProps workInProgress.pendingProps;const oldProps workInProgress.memoizedProps;const newValue newProps.value;// 跳过if (__DEV__) {const providerPropTypes workInProgress.type.propTypes;if (providerPropTypes) {checkPropTypes(providerPropTypes,newProps,prop,Context.Provider,ReactCurrentFiber.getCurrentFiberStackInDev,);}}// 注意这里pushProvider(workInProgress, newValue);if (oldProps ! null) {const oldValue oldProps.value;const changedBits calculateChangedBits(context, newValue, oldValue);if (changedBits 0) {// 没有更新// No change. Bailout early if children are the same.if (oldProps.children newProps.children !hasLegacyContextChanged()) {return bailoutOnAlreadyFinishedWork(current,workInProgress,renderExpirationTime,);}} else {// 存在更新// The context value changed. Search for matching consumers and schedule// them to update.propagateContextChange(workInProgress,context,changedBits,renderExpirationTime,);}}const newChildren newProps.children;reconcileChildren(current, workInProgress, newChildren, renderExpirationTime);return workInProgress.child; }关于 const context: ReactContextany providerType._context;// packages/react/src/ReactContext.js#L53 // 在 createContext 函数内 context.Provider {$$typeof: REACT_PROVIDER_TYPE,_context: context, };进入 pushProvider// packages/react-reconciler/src/ReactFiberNewContext.js#L55 export function pushProviderT(providerFiber: Fiber, nextValue: T): void {const context: ReactContextT providerFiber.type._context;// isPrimaryRenderer 来自 ReactFiberHostConfig.js// 这个值在 dom环境中是 trueif (isPrimaryRenderer) {// 这个 valueCursor 记录的是 当前这个树下面一共经历了几个provider它对应的值// consumer 也就是 context 它的 value 去获取是通过赋制在它上面的这个 _currentValue 来进行一个获取的push(valueCursor, context._currentValue, providerFiber);// 所以, 这跟最终去获取这个 consumer 上面的 context 的时候跟这个 valueCursor 是没有任何关系的context._currentValue nextValue;if (__DEV__) {warningWithoutStack(context._currentRenderer undefined ||context._currentRenderer null ||context._currentRenderer rendererSigil,Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.,);context._currentRenderer rendererSigil;}} else {push(valueCursor, context._currentValue2, providerFiber);context._currentValue2 nextValue;if (__DEV__) {warningWithoutStack(context._currentRenderer2 undefined ||context._currentRenderer2 null ||context._currentRenderer2 rendererSigil,Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.,);context._currentRenderer2 rendererSigil;}} }进入 calculateChangedBitsexport function calculateChangedBitsT(context: ReactContextT,newValue: T,oldValue: T, ) {// Use Object.is to compare the new context value to the old value. Inlined// Object.is polyfill.// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is// 使用这种方法可更准确判断两个值是否相等, 符合下面条件被认为是全等的if ((oldValue newValue (oldValue ! 0 || 1 / oldValue 1 / (newValue: any))) ||(oldValue ! oldValue newValue ! newValue) // eslint-disable-line no-self-compare) {// No change 没有变化return 0;} else {// 注意这里 _calculateChangedBits 这个API未开放直接忽略即可const changedBits typeof context._calculateChangedBits function? context._calculateChangedBits(oldValue, newValue): MAX_SIGNED_31_BIT_INT;if (__DEV__) {warning((changedBits MAX_SIGNED_31_BIT_INT) changedBits,calculateChangedBits: Expected the return value to be a 31-bit integer. Instead received: %s,changedBits,);}return changedBits | 0; // | 0 这里是去除小数部分} }上述 (oldValue ! 0 || 1 / oldValue 1 / (newValue: any) 表示 -0 ! 0上述 oldValue ! oldValue newValue ! newValue 表示 NAN ! NAN上述 MAX_SIGNED_31_BIT_INT 转换成2进制就是 32 位 的 1以上判断就是 除了全等就是 MAX_SIGNED_31_BIT_INT 进入 propagateContextChangeexport function propagateContextChange(workInProgress: Fiber,context: ReactContextmixed,changedBits: number,renderExpirationTime: ExpirationTime, ): void {// 拿到 当前 provider 的第一个子节点let fiber workInProgress.child;if (fiber ! null) {// Set the return pointer of the child to the work-in-progress fiber.fiber.return workInProgress;}// 对子节点进行遍历while (fiber ! null) {let nextFiber;// Visit this fiber.let dependency fiber.firstContextDependency; // 读取这个属性// 存在则进入循环if (dependency ! null) {do {// Check if the context matches.// changedBits 是32位的二进制数都是1// 只要 dependency.observedBits 不是0dependency.observedBits changedBits 就不是 0// dependency.context context 表示遍历过程中的组件是依赖于这个当前的context的// 如果这个context的变化那么说明它要重新渲染// 同时它去判断它提供的这个 observedBits 跟 changedBits 它们是有相交的部分的// 说明它依赖的部分也变化了, 通过这种方式判断这个组件其实是需要更新了if (dependency.context context (dependency.observedBits changedBits) ! 0) {// Match! Schedule an update on this fiber.// 这个组件如果需要更新除非是他自己调用了setState来创建了一个更新// 不然的话没有外部的方式让他去可以更新这种情况// 因为我们在 beginWork 的时候开始是要判断每一个组件自己的 expirationTime 的// 如果那个组件它本身没有创建过更新那么它的 expirationTime 是 nowork// 是nowork的话它就直接跳过更新了这明显不符合我们这边的一个context的一个需求// context这边它就遍历到这个节点的时候发现它依赖这个context如何更新// 通过主动去创建 update并且设置你的 update.tag 是 ForceUpdate// 这其实没有state的一个更新但是你必须要更新// 因为依赖了这个contextcontext更新了所以强制更新一下// 然后把这个update执行 enqueueUpdate 一下这样的话// 在后续要更新到这个组件的时候它就会发现它上面是有update的, 需要去更新它if (fiber.tag ClassComponent) {// Schedule a force update on the work-in-progress.const update createUpdate(renderExpirationTime);update.tag ForceUpdate;// TODO: Because we dont have a work-in-progress, this will add the// update to the current fiber, too, which means it will persist even if// this render is thrown away. Since its a race condition, not sure its// worth fixing.enqueueUpdate(fiber, update);}// 同时这边创建 update 是不够的还要对这个 fiber 它的 expirationTime 进行一个操作// 要看它如果目前它的 expirationTime 的优先级是要大于我当前正在渲染这次 expirationTime 的// 那么我就把它的 expirationTime 设置为这次 update让它在这次渲染过程当中肯定会被更新到if (fiber.expirationTime renderExpirationTime) {fiber.expirationTime renderExpirationTime;}// 不仅要在这个 workingprogress 上面去设置我还要对它的 alternate也就是current也要进行一个设置// 因为这个东西它们应该是要被同步的let alternate fiber.alternate;if (alternate ! null alternate.expirationTime renderExpirationTime) {alternate.expirationTime renderExpirationTime;}// Update the child expiration time of all the ancestors, including// the alternates.// 因为在这个过程当中给这个组件创建了一个update// 代表的意思是我父链上面的每一个节点它的 childExpirationTime 有可能会被改变// 同样的要执行一遍类似于我们在 scheduleWorkToRoot 的时候的做的事情就是设置它的 childExpirationTimelet node fiber.return;while (node ! null) {alternate node.alternate;if (node.childExpirationTime renderExpirationTime) {node.childExpirationTime renderExpirationTime;if (alternate ! null alternate.childExpirationTime renderExpirationTime) {alternate.childExpirationTime renderExpirationTime;}} else if (alternate ! null alternate.childExpirationTime renderExpirationTime) {alternate.childExpirationTime renderExpirationTime;} else {// Neither alternate was updated, which means the rest of the// ancestor path already has sufficient priority.break;}node node.return;}}// 最后设置nextFiber fiber.child;dependency dependency.next; // 从这里可以看出 dependency 它也是可以有多个的} while (dependency ! null);} else if (fiber.tag ContextProvider) {// Dont scan deeper if this is a matching providernextFiber fiber.type workInProgress.type ? null : fiber.child;} else {// Traverse down.nextFiber fiber.child;}// 接下去和很多地方差不多的就是它往子树上去找// 如果子树上没有了它就往它的兄弟节点去找// 就是相当于要把我们的这个provider当前的这个组件它的子树的每一个节点去遍历到// 并且找到有 firstContextDependency 这个属性的这些节点// 给它去创建更新的一个过程if (nextFiber ! null) {// Set the return pointer of the child to the work-in-progress fiber.nextFiber.return fiber;} else {// No child. Traverse to next sibling.nextFiber fiber;while (nextFiber ! null) {if (nextFiber workInProgress) {// Were back to the root of this subtree. Exit.nextFiber null;break;}let sibling nextFiber.sibling;if (sibling ! null) {// Set the return pointer of the sibling to the work-in-progress fiber.sibling.return nextFiber.return;nextFiber sibling;break;}// No more siblings. Traverse up.nextFiber nextFiber.return;}}fiber nextFiber;} }关于 firstContextDependency 在 packages/react-reconciler/src/ReactFiberBeginWork.js#L1415 中的 updateContextConsumer 函数中 调用了 prepareToReadContext 函数, 在这个函数中 workInProgress.firstContextDependency null; 接下去调用了 readContext 获取到 newValue 在 lastContextDependency 为 null 的时候 设置了 currentlyRenderingFiber.firstContextDependency lastContextDependency contextItem; 这是第一次进来的逻辑对于 consumer 的情况已经够了只会调这么一次一个consumer 对应一个 provider 的只会有一个context这里面有很多变量控制和单项链表的数据结构来进行存储不同的 context猜测是为了实现支持 hooks 的环境里面一个 function component里面是可以读取多个context的使用的就是 useContext 这个API, 读取多个context说明这个function component是依赖于多个context provider那么这个时候我们就要在这个 firstcontextdependency 上面去设置一个链表了能够让我们在有多个context的情况下每个context变化都能让这个function component去执行一次更新后续的contextitem直接设置为当前的这个next因为这个contextItem里面是有个next的指针的指向一个它依赖的context就可以了 拿到 newValue 之后调用 render 拿到 newChildren之后reconcileChildren 就完成了这就是 consumer 的一个更新过程 注意在之前的 packages/react-reconciler/src/ReactFiberClassComponent.js#L997 里面 const contextType ctor.contextType; 声明了一个叫做 contextType 的这么一个属性这个属性拿到之后就可以去 readContext 对于 updateClassComponent packages/react-reconciler/src/ReactFiberBeginWork.js#L428 也会调用 prepareToReadContext所以对于 class component 这个fiber对象也会给它设置 firstContextDependency 这个属性的 这就是在 propagateContextChange 这个方法里面可以看到 它只有对于class component它才会去创建一个update对于consumer它是不会去创建update的因为consumer它不是update的一个载体我们只需需要给它设置 expirationTime 就可以了, 不需要给它建update来告诉它我需要 forceUpdate因为在 consumer 中如果需要更新就会执行更新的流程它没有像 class component可以通过 scu 这种方式的规避一个组件的更新的流程 总结 以上就是新的context API它的一个实现过程最主要的就是通过去更新 provider 的时候给这个context它的 _currentValue 设置了一个值设置的这个值就是新的context它提供的这个value以此让我们的consumer可以去获取到这个值可以看到它 readcontext 的时候最后是有一句代码的return isPrimaryRenderer ? context._currentValue : context._currentValue2;这个才是真正返回值的情况, 前面是处理它这个context的依赖对于 provider 更新了之后如何去通知一个consumer依赖的那个组件通过手动的去遍历它的所有子节点, 然后去给它指定它的 expirationTime告诉后续的更新的流程里面这个依赖于我的context所以它需要去更新而且对于 class component要单独为它去创建一个update这就是 provider 和 consumer 这种新的 context API 它的一个实现过程
http://www.zqtcl.cn/news/48825/

相关文章:

  • 深圳网站搭建找谁唐山做企业网站公司
  • 池州北京网站建设外贸建站哪好
  • 无锡企业网站排名优化wordpress钩子大全
  • 上海高端网站定制重庆工程造价信息
  • 网站载入页面怎么做福建省建建设行业信用评分网站
  • 上海服装网站建设惠州百度seo电话
  • 沃然建站平台官网做微信小程序和做网站
  • 金阊公司网站建设电话学校教务网站的设计与实现
  • 网站地图设计做网站需要会语言吗
  • 里水哪里做有做网站同仁行业网站建设报价
  • 商城网站设计与实现江苏建设通网站
  • 网站建设作用个人网站优秀
  • 做301网站打不开定制型网站建设价格
  • 湖南公司响应式网站建设价位泗阳网站定制
  • 河北seo网站优化报价多店铺开源商城系统
  • 30岁做网站运营公司取名大全最新版的
  • 南京市招办南京网站设计望野赏析
  • 如何查询网站空间商建自己的个人网站
  • 浙江省网站icp备案网站自助服务建设策划
  • 石家庄学做网站建设培训班加工厂怎么找订单
  • 网站建设算软件还是硬件在线做简单的网站吗
  • 房地产怎么做网站推广企业解决方案案例分析
  • 怎么看网站开发的技术湖南网站推广营销设计
  • 网站版权模板青岛金融网站建设
  • 谷歌排名网站优化网站搭建赚钱吗
  • 做旅游的网站有哪些网络营销有哪些内容
  • 做二手房网站动漫制作教学
  • 潍坊做网站的网络公司简阳seo排名优化培训
  • 写作网站的文风1元云主机
  • 上海市城乡建设网站自己电脑做网站服务器系统