上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

React16源码: React中context-stack的源码实现

guduadmin553月前

context-stack

1 ) 概述

  • 在 context 内部有一个概念是 stack
    • 有一个唯一的stack
    • 里面保存各种各样的东西
    • stack的特性
      • 在更新节点的时候,会把相关的信息入栈
        • 在因为stack就是栈,在里面会存储各种各样的信息
        • 在更新节点的时候,每一个节点的信息都会推入这个stack
        • 完成节点更新的时候,相关的信息需要出栈
          • 因为栈是一个先入后出的这么一个数据结构
          • 这正好对应于 react的更新过程中的 beginWork 是从头到尾
          • 沿着子树的一侧这么下来的一个过程,这个时候我们从头到尾,推入了相关的信息
          • 然后在 completeUnitOfWork 的时候,我们又是从尾到头去进行一个完成节点更新的操作
          • 这个时候刚好是一个相反的顺序
          • 在这个相反的顺序当中,又可以同时出栈,这样的话, 就可以保证我们的栈从更新开始到最终更新结束
          • 因为从更新开始到更新结束,都是要回到 root 节点,它这个栈更新开始的时候是空的
          • 更新结束的时候,也刚好变成一个空的状态
          • 这就是在更新时入栈,在完成节点时出栈
          • 在这个栈的数据结构中可以用不同的cursor来记录不同的信息
            • react的这个stack的实现过程中,它需要存的信息是非常多的
            • 比如说有新的 contextAPI 也有老的 contextAPI
            • 还有跟 HostComponent 相关的一些信息,还有container相关的一些信息
            • 这些信息之间是互不干涉,没有任何关联的,这些信息都要存在同一个stack里面
            • 通过 cursor 去标记这些相关性的信息自己处于哪个位置

              2 )源码

              定位到 packages/react-reconciler/src/ReactFiberStack.js

              /**
               * Copyright (c) Facebook, Inc. and its affiliates.
               *
               * This source code is licensed under the MIT license found in the
               * LICENSE file in the root directory of this source tree.
               *
               * @flow
               */
              import type {Fiber} from './ReactFiber';
              import warningWithoutStack from 'shared/warningWithoutStack';
              export type StackCursor = {
                current: T,
              };
              const valueStack: Array = [];
              let fiberStack: Array;
              if (__DEV__) {
                fiberStack = [];
              }
              let index = -1;
              function createCursor(defaultValue: T): StackCursor {
                return {
                  current: defaultValue,
                };
              }
              function isEmpty(): boolean {
                return index === -1;
              }
              function pop(cursor: StackCursor, fiber: Fiber): void {
                if (index < 0) {
                  if (__DEV__) {
                    warningWithoutStack(false, 'Unexpected pop.');
                  }
                  return;
                }
                if (__DEV__) {
                  if (fiber !== fiberStack[index]) {
                    warningWithoutStack(false, 'Unexpected Fiber popped.');
                  }
                }
                cursor.current = valueStack[index];
                valueStack[index] = null;
                if (__DEV__) {
                  fiberStack[index] = null;
                }
                index--;
              }
              function push(cursor: StackCursor, value: T, fiber: Fiber): void {
                index++;
                valueStack[index] = cursor.current;
                if (__DEV__) {
                  fiberStack[index] = fiber;
                }
                cursor.current = value;
              }
              function checkThatStackIsEmpty() {
                if (__DEV__) {
                  if (index !== -1) {
                    warningWithoutStack(
                      false,
                      'Expected an empty stack. Something was not reset properly.',
                    );
                  }
                }
              }
              function resetStackAfterFatalErrorInDev() {
                if (__DEV__) {
                  index = -1;
                  valueStack.length = 0;
                  fiberStack.length = 0;
                }
              }
              export {
                createCursor,
                isEmpty,
                pop,
                push,
                // DEV only:
                checkThatStackIsEmpty,
                resetStackAfterFatalErrorInDev,
              };
              
              • 首先定义一个非常重要的变量叫做 valueStack,它是一个数组
              • 接下去这边有一个 fiberStack,它只是用于开发的过程当中, 可以先忽略它
              • 定义一个全局 index
                • 注意这个 index 就是对应 valueStack 目前存数据存在的哪个位置
                • 接下去, 声明了一个方法叫做 createCursor
                  • 直接 return 了一个新的对象
                  • 这个对象里面有一个 current 属性
                  • 在创建的时候传入的一个 defaultValue 给 current 赋值
                  • 它是一个 pure 的对象,没有任何其他的一些特性
                  • 注意
                    • 这整个文件,它对应的是一个模块
                    • valueStack 定义一些什么东西
                    • 它里面的所有的数据都是有关联性的
                    • 主要的数据也就是 valuestack 跟 index 是在这个模块里面
                    • 它其他的数据都是在外部,使用的时候才会创建的
                    • 这个 index 它本来是标记 valueStack 对应数据存在哪个位置
                    • 可以通过它是否等于 -1 来判断我们目前的 valueStack 它是否是一个空的数组
                    • 接下去的 pop 方法
                      • 如果 index < 0
                        • 说明 valueStack 里面没有任何的数据,直接return
                        • 因为我们没有任何东西是可以推出来的
                        • 读取 index 在 valueStack 对应的 value 存入 cursor.current
                          • 因为在推入的时候,就是把老的值存到 valueStack上面,然后新的值它等于新设置的值
                          • 如果要 pop 的时候,对应的肯定要把老的那个值再赋值回来
                          • 将 index 对应在 valueStack 中的 value 置空
                          • 将 index –
                          • 接下去的 push 方法
                            • 它接收的参数 cursor, value, fiber
                            • cursor 是通过 createCursor 这个方法来创建的一个游标对象
                            • 将 index ++
                            • 将老的 value (cursor.current) 推入到 栈 当中
                            • 将当前 cursor.current 指向传进来的 value
                            • 注意,在一次 push 中新的 value 不会入栈的
                            • checkThatStackIsEmpty
                              • 这个只有在开发时会用到,其实就跟 isEmpty 是一样的
                              • 它判断一下index是否等于 -1,然后进行一个warning
                              • resetStackAfterFatalErrorInDev
                                • dev 相关变量,无需过多关注
                                • 就是重置了一些值
                                • 注意
                                  • 如果在对 valueStack 进行操作的过程中,顺序是不一样的
                                  • 比如说,我有三种不同的数据类型,就有三个不同的cursor
                                  • 3个不同的 cursor 它们推入的这些数据,保存的不一样
                                  • 比如说,我目前这个数组先推入了一个a,然后再推入了一个b,然后再推入了一个c
                                  • 它们分别对应的是 cursor1(c1), cursor2(c2), cursor3(c3),它们想要读取的数据应该是这样的
                                  • 即 [a, b, c] => c1, c2, c3
                                  • 在 pop 的时候,可能先 pop 了 c1,但是我拿到的是却是 c3 对应的数据 c
                                  • 这个就是我们不想要出现的一个情况,实际上这个文件内没有解决这个问题
                                  • 因为react在更新的过程当中,先从 beginWork 里面推数据
                                  • 然后在 completeUnitOfWork 里面去提出数据
                                  • 这个过程中,它始终保持着 cursor 的一一对应关系
                                  • 也就是说我推进来的是c1, c2, c3的顺序
                                  • 推出的时候,要先推出 c3,再推出 c2,再推出 c1
                                  • 它们拿到的值都是一个一一对应的关系
                                  • 这是react在使用这个stack模块的时候去控制的
                                  • 而不是在我们这个模块内部去解的这个问题
                                  • 比如说 context 它一个入栈,出栈的一个情况的时候就会有这个调用的过程
                                  • 这个目前先跳过

网友评论

搜索
最新文章
热门文章
热门标签
 
 梦见自己砍人血腥场面  梦里见鬼是什么征兆  梦见红白喜事一起出现是什么意思