react 获取url参数_react源码个人笔记-版本17.0.0(笔记08)

8b82ee856d3fdcc7ee34646be034b539.png

// getRootHostContainer(1)

// url: src/react/packages/react-reconciler/src/ReactFiberHostContext.old.js
function getRootHostContainer(): Container {
 // 获取实例
 const rootInstance = requiredContext(rootInstanceStackCursor.current);
 return rootInstance;
  // 返回的结果 : div#root,就是挂载的元素
}

// 备注: 返回挂载的节点, div#root
// 
// requiredContext 
function requiredContext<Value>(c: Value | NoContextT): Value {
  invariant(
    c !== NO_CONTEXT,
    'Expected host context to exist. This error is likely caused by a bug ' +
      'in React. Please file an issue.',
  );
  return (c: any);
}

//  备注: 读取节点的内容

// getHostContext
function getHostContext(): HostContext {
  const context = requiredContext(contextStackCursor.current);
  return context;
}
// 备注: 返回contextStackCursor.current  的内容

const NO_CONTEXT: NoContextT = ({}: any);
// 备注: 主要获取创建dom元素的需要配置的参数。

// createInstance(2)

// url: src/react/packages/react-dom/src/client/ReactDOMHostConfig.js
export function createInstance(
  type: string,  // 元素的名称
  props: Props,  // props
  rootContainerInstance: Container,  // div#root
  hostContext: HostContext, //  "http://www.w3.org/1999/xhtml"
  internalInstanceHandle: Object,  // fiber 对象
): Instance {
  let parentNamespace: string;
  // 跳过
  if (__DEV__) {
     // 忽略
  } else {
    // 设置命名空间
    //hostContext : "http://www.w3.org/1999/xhtml"
    parentNamespace = ((hostContext: any): HostContextProd);
  }
  // 元素节点创建
  const domElement: Instance = createElement(
    type,
    props,
    rootContainerInstance,
    parentNamespace,
  );
    // 设置fiber 和node 的关系
  precacheFiberNode(internalInstanceHandle, domElement);
  // 设置ndoe 和props的关系
  updateFiberProps(domElement, props);
  return domElement;
}
// 备注: 元素节点的创建, 设置元素和fiber, 元素和 props的关系。

// precacheFiberNode (3)

// url: src/react/packages/react-dom/src/client/ReactDOMComponentTree.js
export function precacheFiberNode(
  hostInst: Fiber,
  node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
): void {
  (node: any)[internalInstanceKey] = hostInst;
  // 
}
// 备注:节点的关系设置 node 节点和fiber 关系
// node
const randomKey = Math.random()
  .toString(36)
  .slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;

// url: src/react/packages/react-dom/src/client/ReactDOMComponentTree.js

export function updateFiberProps(
  node: Instance | TextInstance | SuspenseInstance,
  props: Props,
): void {
  (node: any)[internalPropsKey] = props;
}
// 备注: 设置node 和props 的关系
// props
const internalPropsKey = '__reactProps$' + randomKey;
const randomKey = Math.random()
  .toString(36)
  .slice(2);

// createElement (4)

// url: src/react/packages/react-dom/src/client/ReactDOMComponent.js
export function createElement(
  type: string,
  props: Object,
  rootContainerElement: Element | Document,
  parentNamespace: string,
): Element {
  let isCustomComponentTag;
  // 节点的创建
  const ownerDocument: Document = getOwnerDocumentFromRootContainer(
    rootContainerElement,
  );
  // namespace 的处理
  let domElement: Element;
  let namespaceURI = parentNamespace;
  if (namespaceURI === HTML_NAMESPACE) {  // 'http://www.w3.org/1999/xhtml';
// HTML_NAMESPACE:"http://www.w3.org/1999/xhtml"
    // 处理
    namespaceURI = getIntrinsicNamespace(type);
  }
  if (namespaceURI === HTML_NAMESPACE) {
    // 正常路线

    // script 的处理
    if (type === 'script') {
      const div = ownerDocument.createElement('div');
      div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
      // This is guaranteed to yield a script element.
      const firstChild = ((div.firstChild: any): HTMLScriptElement);
      domElement = div.removeChild(firstChild);
    } else if (typeof props.is === 'string') {  
      // is 的处理
      // $FlowIssue `createElement` should be updated for Web Components
      domElement = ownerDocument.createElement(type, {is: props.is});
    } else {
      // 普通的类型创建
      domElement = ownerDocument.createElement(type); 
      if (type === 'select') {
        const node = ((domElement: any): HTMLSelectElement);
        if (props.multiple) {  // 设置multiple 属性
          node.multiple = true;
        } else if (props.size) { // 设置size 属性
          node.size = props.size;
        }
      }
    }
  } else {
    // 不是htmmns 时, 创建
    domElement = ownerDocument.createElementNS(namespaceURI, type);
  }
  // 跳过的部分
  // dev 部分,省略
  return domElement;
}
// 备注: 根据命名空间参数,和元素明晨创建一个dom节点。


//  getIntrinsicNamespace()
// url: src/react/packages/react-dom/src/shared/DOMNamespaces.js
export function getIntrinsicNamespace(type: string): string {
  switch (type) {
    case 'svg':
      return SVG_NAMESPACE;
    case 'math':
      return MATH_NAMESPACE;
    default:
      return HTML_NAMESPACE;
  }
}
// 备注: 命名空间的转换
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
const MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';

// getOwnerDocumentFromRootContainer(5)

// url: src/react/packages/react-dom/src/client/ReactDOMComponent.js
function getOwnerDocumentFromRootContainer(
  rootContainerElement: Element | Document,  // container  
): Document {
  return rootContainerElement.nodeType === DOCUMENT_NODE
    ? (rootContainerElement: any)  // 
    : rootContainerElement.ownerDocument;  // window.document
    // 多平台的兼容行 
}
// 备注:多平台的兼容返回 window.document


// HostRoot节点的completeWork 中为一个空函数
// url: src/react/packages/react-reconciler/src/ReactFiberCompleteWork.old.js
updateHostContainer = function(workInProgress: Fiber) {
    // Noop
};
// 备注: hostRoot节点中的completeWork为一个空函数

// appendAllChildren (6)

// url: src/react/packages/react-reconciler/src/ReactFiberCompleteWork.old.js 
appendAllChildren = function(
    parent: Instance, // dom 
    workInProgress: Fiber, // fiber
    needsVisibilityToggle: boolean,
    isHidden: boolean,
  ) {
    // 只会执行第一次的dom 或text 处理, 第二层不处理
    // 第一个child
    let node = workInProgress.child;
    while (node !== null) {
      // 原生的dom 或文本
      if (node.tag === HostComponent || node.tag === HostText) {// 。
        appendInitialChild(parent, node.stateNode);
        // 只执行一次, 执行一层
      } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {
        // 跳过
     //  export const enableFundamentalAPI = false;
        appendInitialChild(parent, node.stateNode.instance);
      } else if (node.tag === HostPortal) {
        // HostPortal 不处理
        // 空
      } else if (node.child !== null) { // 上述条件都不符合
        // 更新为子节点
        node.child.return = node;
        node = node.child;
        continue;  // 跳出这个
      }
      // 这个子树已经结束了
      if (node === workInProgress) {
        return;
      }
      // 没有兄弟节点的时候
      while (node.sibling === null) {
        // 返回为null
        if (node.return === null || node.return === workInProgress) {
          return;
        }
        node = node.return;
      }
      // 遍历
      node.sibling.return = node.return;  // 不停的遍历兄弟节点
      node = node.sibling;
    }
  };
// 备注: 遍历workInProgress 的子节点, 当为文本或dom元素,直接添加为传入的dom子节点, 类型为HostPortal 跳过
// 不添加, 其他类型时, 深度遍历, 直到文本节点或dom, 添加到添加为传入的dom子节点。
// 只添加一层, 不进行深度遍历

// 节点的添加
// url: src/react/packages/react-dom/src/client/ReactDOMHostConfig.js
export function appendInitialChild(
  parentInstance: Instance,
  child: Instance | TextInstance,
): void {
  // 节点的挂载
  parentInstance.appendChild(child);  
}
// 备注: 节点的增加  : document.appendChild

// finalizeInitialChildren(7)

// url: src/react/packages/react-dom/src/client/ReactDOMHostConfig.js
export function finalizeInitialChildren(
  domElement: Instance,  // dom节点
  type: string, // dom节点的字符标示
  props: Props, // 属性
  rootContainerInstance: Container, // div#root
  hostContext: HostContext, // 
): boolean {
  // 设置属性
  setInitialProperties(domElement, type, props, rootContainerInstance);
  return shouldAutoFocusHostComponent(type, props);  //节点是否需要聚焦
}
// 备注: 执行setInitialProperties 函数, 并将shouldAutoFocusHostComponent 的结果返回。

// setInitialProperties (8)

// url: src/react/packages/react-dom/src/client/ReactDOMComponent.js
export function setInitialProperties(
  domElement: Element, // dom节点
  tag: string, // dom节点的字符标示
  rawProps: Object, // 属性
  rootContainerElement: Element | Document,  // div#root
): void {
  // 是否是的组件
  const isCustomComponentTag = isCustomComponent(tag, rawProps);
  let props: Object;
  switch (tag) {  // 标签名称
    case 'dialog':  // dialog
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('cancel', domElement);
      listenToNonDelegatedEvent('close', domElement);
      props = rawProps;
      break;
    case 'iframe':
    case 'object':
    case 'embed':
       // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('load', domElement);
      props = rawProps;
      break;
    case 'video':
    case 'audio':
      for (let i = 0; i < mediaEventTypes.length; i++) {
        // 直接挂载在dom元素上事件
        listenToNonDelegatedEvent(mediaEventTypes[i], domElement);
      }
      props = rawProps;
      break;
    case 'source': // source
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('error', domElement);
      props = rawProps;
      break;
    case 'img':
    case 'image':
    case 'link':
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('error', domElement);
      listenToNonDelegatedEvent('load', domElement);
      props = rawProps;
      break;
    case 'details':
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('toggle', domElement);
      props = rawProps;
      break;
    case 'input':  // input 的处理
    // 基础属性设置
      ReactDOMInputInitWrapperState(domElement, rawProps);
      props = ReactDOMInputGetHostProps(domElement, rawProps);
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('invalid', domElement);
      if (!enableEagerRootListeners) { //true;
    // export const enableEagerRootListeners = true;
        ensureListeningTo(rootContainerElement, 'onChange', domElement);
      }
      break;
    case 'option': // option
      ReactDOMOptionValidateProps(domElement, rawProps);
      props = ReactDOMOptionGetHostProps(domElement, rawProps);
      break;
    case 'select':  // select
      ReactDOMSelectInitWrapperState(domElement, rawProps);
      props = ReactDOMSelectGetHostProps(domElement, rawProps);
      // 直接挂载在dom元素上事件
      listenToNonDelegatedEvent('invalid', domElement);
      if (!enableEagerRootListeners) {  // enableEagerRootListeners : ture;
// 事件怎么挂载?
       // 直接挂载在dom元素上事件
        ensureListeningTo(rootContainerElement, 'onChange', domElement);
      }
      break;
    case 'textarea': // textarea 的处理
      ReactDOMTextareaInitWrapperState(domElement, rawProps);
      props = ReactDOMTextareaGetHostProps(domElement, rawProps);
    
      listenToNonDelegatedEvent('invalid', domElement);
      if (!enableEagerRootListeners) {
       // 直接挂载在dom元素上事件
        ensureListeningTo(rootContainerElement, 'onChange', domElement);
      }
      break;
    default:
      props = rawProps;
  }
  // 验证props
  assertValidProps(tag, props);
// 属性设置
  setInitialDOMProperties(
    tag,
    domElement,
    rootContainerElement,
    props,
    isCustomComponentTag,
  );
  switch (tag) {
    case 'input':
      // 什么
  
      track((domElement: any));
      ReactDOMInputPostMountWrapper(domElement, rawProps, false);
      break;
    case 'textarea':
      track((domElement: any));
      ReactDOMTextareaPostMountWrapper(domElement, rawProps);
      break;
    case 'option':
      ReactDOMOptionPostMountWrapper(domElement, rawProps);
      break;
    case 'select':
      ReactDOMSelectPostMountWrapper(domElement, rawProps);
      break;
    default:
      if (typeof props.onClick === 'function') {
        // TODO: This cast may not be sound for SVG, MathML or custom elements.
        trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
      }
      break;
  }
}
// 备注: (1)对一些元素进行非代理的事件绑定, (2)props 的校验,(3)对dom元素设置属性,
// style, innerHTML, attribute, 
// (4)其他处理

// isCustomComponent (9)

// url: src/react/packages/react-dom/src/shared/isCustomComponent.js
function isCustomComponent(tagName: string, props: Object) {
  if (tagName.indexOf('-') === -1) {  // 不具有- 是
    return typeof props.is === 'string'; // 且props 中is属性值  为字符
  }
  switch (tagName) {
    case 'annotation-xml':
    case 'color-profile':
    case 'font-face':
    case 'font-face-src':
    case 'font-face-uri':
    case 'font-face-format':
    case 'font-face-name':
    case 'missing-glyph':
      return false;
    default:
      return true;
  }
}
// 备注: 是否是自定义组件/元素?

// listenToNonDelegatedEvent(9)

// 监听  进行不代理的事件绑定
// url: src/react/packages/react-dom/src/events/DOMPluginEventSystem.js
export function listenToNonDelegatedEvent(
  domEventName: DOMEventName,  // 事件名称
  targetElement: Element,  // 触发源
): void {
  const isCapturePhaseListener = false;  // 在捕获阶段触发?
  const listenerSet = getEventListenerSet(targetElement); // Set 的结构
  const listenerSetKey = getListenerSetKey(  // 将名称和是否捕获转换为key
    domEventName,
    isCapturePhaseListener,
  ); // 转化成的key
  if (!listenerSet.has(listenerSetKey)) {  // 不具有
    addTrappedEventListener(  //  后面再解析
      targetElement,  // 触发元素
      domEventName,  // 事件名称
      IS_NON_DELEGATED, // export const IS_NON_DELEGATED = 1 << 1;
      isCapturePhaseListener,  //是否捕获
    );
    listenerSet.add(listenerSetKey);  // 设置key 
  }
}
// 备注:直接在元素上绑定事件, 特定的事件直接绑定在元素上。

// getEventListenerSet (10)

// url: src/react/packages/react-dom/src/client/ReactDOMComponentTree.js
export function getEventListenerSet(node: EventTarget): Set<string> {
  // 节点的监听set 获取
  let elementListenerSet = (node: any)[internalEventHandlersKey]; // 生成的key
  if (elementListenerSet === undefined) {
    elementListenerSet = (node: any)[internalEventHandlersKey] = new Set(); 
    // 是一个set 结构
  }
  return elementListenerSet;
}

const internalEventHandlersKey = '__reactEvents$' + randomKey;
const randomKey = Math.random()
  .toString(36)
  .slice(2);

// 备注: 在dom 节点上增加internalEventHandlersKey 属性,  结构为一个Set , 储存当前
// 元素上挂载的事件

//  getListenerSetKey
// url: src/react/packages/react-dom/src/events/DOMPluginEventSystem.js
export function getListenerSetKey(
  domEventName: DOMEventName,  // 事件名称
  capture: boolean,  // 是否捕获
): string {
  return `${domEventName}__${capture ? 'capture' : 'bubble'}`;
}
// 备注: 将事件名称和 是否捕获 转化的字段,生成一个事件的key, 这么理解,一个元素只能挂载一个对应
// 的事件

// ReactDOMInputInitWrapperState(11)

import {
   initWrapperState as ReactDOMInputInitWrapperState,
} from './ReactDOMInput';

// url: src/react/packages/react-dom/src/client/ReactDOMInput.js
export function initWrapperState(element: Element, props: Object) {
  // 节点
  const node = ((element: any): InputWithWrapperState); // 节点
  // 默认值
  const defaultValue = props.defaultValue == null ? '' : props.defaultValue;

  node._wrapperState = {
    initialChecked:  // 初始checked
      props.checked != null ? props.checked : props.defaultChecked,
    initialValue: getToStringValue(  // 获取值
      props.value != null ? props.value : defaultValue,
    ),
    controlled: isControlled(props),
  };
}
// 备注: 对于input类型节点node 上挂载_wrapperState 属性,initialChecked: 优先取checked ,
//其次 defaultChecked, initialValue 优先值value, 其次 defaultValue,controlled
// 转化为string
// url : src/react/packages/react-dom/src/client/ToStringValue.js
export function getToStringValue(value: mixed): ToStringValue {
  switch (typeof value) {
    case 'boolean':
    case 'number':
    case 'object':
    case 'string':
    case 'undefined':
      return value;
    default:
      // function, symbol are assigned as empty strings
      return '';
  }
}
// 备注: 转化为字符串
// url: src/react/packages/react-dom/src/client/ReactDOMInput.js
function isControlled(props) {
  // checkbox 或radio
  const usesChecked = props.type === 'checkbox' || props.type === 'radio';
  return usesChecked ? props.checked != null : props.value != null;
}
// 备注:(1) type为checkbox 或radio 时, checked 不为空,其他情况下不为空

// ReactDOMInputGetHostProps (12)

import {
   getHostProps as ReactDOMInputGetHostProps,
} from './ReactDOMInput';

// url: src/react/packages/react-dom/src/client/ReactDOMInput.js
export function getHostProps(element: Element, props: Object) {
  const node = ((element: any): InputWithWrapperState); // 节点
  const checked = props.checked; // 选中
  // 返货hostProps 
  const hostProps = Object.assign({}, props, {
    defaultChecked: undefined,
    defaultValue: undefined,
    value: undefined,
    checked: checked != null ? checked : node._wrapperState.initialChecked, // 原来计算
  });

  return hostProps;
}
// 备注: 获取input 元素的props, 额外增加defaultChecked, defaultValue, value, 
// 和checked

// ReactDOMOptionValidateProps (13)

import {
   validateProps as ReactDOMOptionValidateProps,
} from './ReactDOMOption';

// url: src/react/packages/react-dom/src/client/ReactDOMOption.js
export function validateProps(element: Element, props: Object) {
  if (__DEV__) {
    // This mirrors the code path above, but runs for hydration too.
    // 空函数
  }
}
//  备注: 没有任何处理
import {
  getHostProps as ReactDOMOptionGetHostProps,
} from './ReactDOMOption';
// 获取props
export function getHostProps(element: Element, props: Object) {
  const hostProps = {children: undefined, ...props};
  const content = flattenChildren(props.children);
// 处理children 
  if (content) {
    hostProps.children = content;
  }
  return hostProps;
}
// 备注: 设置options 节点上的props,  在props的基础上增加children;

// 
function flattenChildren(children) {
  let content = '';
 // 遍历
  React.Children.forEach(children, function(child) {
    if (child == null) {
      return;
    }
    content += (child: any);
  });
  return content;
}
// 备注: 返回children , 如果是数组,直接对内部的元素进行拼接。

// ReactDOMSelectInitWrapperState (14)

import {
   initWrapperState as ReactDOMSelectInitWrapperState,
   getHostProps as ReactDOMSelectGetHostProps,
} from './ReactDOMSelect';

//  initWrapperState
// url: src/react/packages/react-dom/src/client/ReactDOMSelect.js
export function initWrapperState(element: Element, props: Object) {
  const node = ((element: any): SelectWithWrapperState);  
  node._wrapperState = {
    wasMultiple: !!props.multiple,
  };
}
// 备注: 设置select 的_wrapperState 属性。属性值为multiple 

// url: src/react/packages/react-dom/src/client/ReactDOMSelect.js
export function getHostProps(element: Element, props: Object) {
  return Object.assign({}, props, {
    value: undefined,
  });
}
// 备注: 获取select 的props; 在原来的基础上增加value: undefined;

// ReactDOMTextareaInitWrapperState (15)

import {
  initWrapperState as ReactDOMTextareaInitWrapperState,
  getHostProps as ReactDOMTextareaGetHostProps,
} from './ReactDOMTextarea';

// url: src/react/packages/react-dom/src/client/ReactDOMTextarea.js
export function initWrapperState(element: Element, props: Object) {
  const node = ((element: any): TextAreaWithWrapperState); // 节点
  let initialValue = props.value;  // 数据
  if (initialValue == null) { //  初始值为null
    let {children, defaultValue} = props; // 获取children 
    if (children != null) {  // children 非空
      // export const disableTextareaChildren = false;
      if (!disableTextareaChildren) {  // true;
        invariant(
          defaultValue == null,
          'If you supply `defaultValue` on a <textarea>, do not pass children.',
        );
        if (Array.isArray(children)) {  // 数组
          invariant(
            children.length <= 1,
            '<textarea> can only have at most one child.',
          );
          children = children[0]; // 获取第一个
        }

        defaultValue = children;
      }
    }
    if (defaultValue == null) {  // 默认值
      defaultValue = '';
    }
    initialValue = defaultValue;  // 初始值
  }

  node._wrapperState = {
    initialValue: getToStringValue(initialValue),
  };
}
// 备注: 获取textarae 的initialValue 值的对象。(1) 优先取value, (2) 再取children (3)
// 最后取值defaultValue

export function getHostProps(element: Element, props: Object) {
  const node = ((element: any): TextAreaWithWrapperState);
  const hostProps = {
    ...props,
    value: undefined,
    defaultValue: undefined,
    children: toString(node._wrapperState.initialValue),
  };

  return hostProps;
}
// 备注: 对于textarea类型, props 包含原来的props , value, default, 和children;

// setInitialDOMProperties(16)

// url: src/react/packages/react-dom/src/client/ReactDOMComponent.js
function setInitialDOMProperties(
  tag: string,
  domElement: Element,
  rootContainerElement: Element | Document,
  nextProps: Object,
  isCustomComponentTag: boolean,
): void {
  // 遍历属性
  for (const propKey in nextProps) {
    // 过滤非自身属性
    if (!nextProps.hasOwnProperty(propKey)) {
      continue;
    }
    const nextProp = nextProps[propKey];
    // style 
    if (propKey === STYLE) {
      // 设置style
      setValueForStyles(domElement, nextProp);
    } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
      // dangerouslySetInnerHTML
      const nextHtml = nextProp ? nextProp[HTML] : undefined;
      if (nextHtml != null) {
        setInnerHTML(domElement, nextHtml);
      }
    } else if (propKey === CHILDREN) {
      if (typeof nextProp === 'string') {  // string 
        // children 属性非空或者 tag 不为textarea
        const canSetTextContent = tag !== 'textarea' || nextProp !== '';  // 非空字符
        if (canSetTextContent) {
          setTextContent(domElement, nextProp);
        }
      } else if (typeof nextProp === 'number') {
        // 数字
        setTextContent(domElement, '' + nextProp); // 属性
      }
    } else if (
      propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
      propKey === SUPPRESS_HYDRATION_WARNING
    ) {
      // 没操作
      // Noop
    } else if (propKey === AUTOFOCUS) {
    // 空
    } else if (registrationNameDependencies.hasOwnProperty(propKey)) {
      // 注册的事件
      if (nextProp != null) {
        if (!enableEagerRootListeners) { // enableEagerRootListeners: true
          // 事件注册
          // export const enableEagerRootListeners = true;
          ensureListeningTo(rootContainerElement, propKey, domElement); // 同16版本有
// 差异, 不在这里注册事件
        } else if (propKey === 'onScroll') { // scroll
          listenToNonDelegatedEvent('scroll', domElement);
        }
      }
    } else if (nextProp != null) {
      // 其他的特性
      setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag);
    }
  }
}
// 备注: 对dom 元素,进行style, children , dangerouslySetInnerHTML 和其他特性的设置

// setValueForStyles(17)

// url: src/react/packages/react-dom/src/shared/CSSPropertyOperations.js
export function setValueForStyles(node, styles) {  // 节点 , style 对象
  const style = node.style;
  // 名称
  for (let styleName in styles) {  // 遍历
    // 过滤非自己拥有的
    if (!styles.hasOwnProperty(styleName)) {
      continue;
    }
    // 游览器的
    const isCustomProperty = styleName.indexOf('--') === 0; // z
    // 样式值
    const styleValue = dangerousStyleValue(
      styleName,  // 属性名
      styles[styleName], // 属性值
      isCustomProperty,  // 
    );
    if (styleName === 'float') {  // float处理
      styleName = 'cssFloat';
    }
    if (isCustomProperty) {  // 自己
      style.setProperty(styleName, styleValue);
    } else {
      style[styleName] = styleValue;  // 其他情况
    }
  }
}
 // 备注: 处理特殊的样式名,处理样式的数据,通过style 设置dom的样式 或者setProperty 
//  设置样式

// dangerousStyleValue(18)

// url: src/react/packages/react-dom/src/shared/dangerousStyleValue.js
function dangerousStyleValue(name, value, isCustomProperty) {
  // 空值校验
  const isEmpty = value == null || typeof value === 'boolean' || value === '';
  if (isEmpty) {
    return '';
  }
 // name不在isCustomProperty 中, 
// // 具有这个属性, 且在这个对象中
  if (
    !isCustomProperty &&   // 非--样式
    typeof value === 'number' &&  // 是一个数字
    value !== 0 &&  // 不是0
    !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])
  ) {
    // px, 一些样式增加px;
    return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers
  }

  return ('' + value).trim();
}
// 备注:(1) 对一些样式值进行空值处理 (2) 判断特定样式,增加px; 
// src/react/packages/react-dom/src/shared/CSSProperty.js
export const isUnitlessNumber = {
  animationIterationCount: true,
  borderImageOutset: true,
  borderImageSlice: true,
  borderImageWidth: true,
  boxFlex: true,
  boxFlexGroup: true,
  boxOrdinalGroup: true,
  columnCount: true,
  columns: true,
  flex: true,
  flexGrow: true,
  flexPositive: true,
  flexShrink: true,
  flexNegative: true,
  flexOrder: true,
  gridArea: true,
  gridRow: true,
  gridRowEnd: true,
  gridRowSpan: true,
  gridRowStart: true,
  gridColumn: true,
  gridColumnEnd: true,
  gridColumnSpan: true,
  gridColumnStart: true,
  fontWeight: true,
  lineClamp: true,
  lineHeight: true,
  opacity: true,
  order: true,
  orphans: true,
  tabSize: true,
  widows: true,
  zIndex: true,
  zoom: true,

  // SVG-related properties
  fillOpacity: true,
  floodOpacity: true,
  stopOpacity: true,
  strokeDasharray: true,
  strokeDashoffset: true,
  strokeMiterlimit: true,
  strokeOpacity: true,
  strokeWidth: true,
};

// setTextContent (19)

// url: src/react/packages/react-dom/src/client/setTextContent.js
const setTextContent = function(node: Element, text: string): void {
  if (text) {
    const firstChild = node.firstChild;  //第一个节点
    if (
      firstChild &&
      firstChild === node.lastChild &&  // 只有一个节点 与最后节点相等
      firstChild.nodeType === TEXT_NODE  // 节点类型为文本
    ) {
      firstChild.nodeValue = text;
      return;
    }
  }
  node.textContent = text;
};
// 备注: (1)设置节点的context; (2)

// createMicrosoftUnsafeLocalFunction(20)

// url: src/react/packages/react-dom/src/shared/createMicrosoftUnsafeLocalFunction.js
const createMicrosoftUnsafeLocalFunction = function(func) {
  // MSApp 存在 且 MSApp.execUnsafeLocalFunction 具有属性
  if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
    return function(arg0, arg1, arg2, arg3) {
      MSApp.execUnsafeLocalFunction(function() {
        return func(arg0, arg1, arg2, arg3);
      });
    };
  } else {
    // 测试没有MSApp
    return func;
  }
};
// 备注: 根据判断MSApp 和 MSApp.execUnsafeLocalFunction 是否存在,返回具体的函数

// setInnerHTML(21)

// url: src/react/packages/react-dom/src/client/setInnerHTML.js
const setInnerHTML = createMicrosoftUnsafeLocalFunction(function(
  node: Element,
  html: {valueOf(): {toString(): string, ...}, ...},
): void {
  if (node.namespaceURI === Namespaces.svg) {  // 命名空间的判断
    //  dev代码,已省略
    if (!('innerHTML' in node)) {
      reusableSVGContainer =
        reusableSVGContainer || document.createElement('div');
      reusableSVGContainer.innerHTML =
        '<svg>' + html.valueOf().toString() + '</svg>';
      const svgNode = reusableSVGContainer.firstChild;
      while (node.firstChild) {
        node.removeChild(node.firstChild);
      }
      while (svgNode.firstChild) {
        node.appendChild(svgNode.firstChild);
      }
      return;
    }
  }
  node.innerHTML = (html: any);  // 直接设置html的内容
});
// 备注: 设置元素节点的innerHTML

// setValueForProperty(22)

// url: src/react/packages/react-dom/src/client/DOMPropertyOperations.js
export function setValueForProperty(
  node: Element,
  name: string,
  value: mixed,
  isCustomComponentTag: boolean,
) {
//  获取对应name的attribet对象
  const propertyInfo = getPropertyInfo(name);  // 获取名称的name 的对象描述
  if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) {
 // 可以被忽略的
    return;
  }
// 一些需要移除的特性
  if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {
    value = null;
  }
  // 名称 或者 为空
  if (isCustomComponentTag || propertyInfo === null) {
    if (isAttributeNameSafe(name)) {  // 符合要求
      const attributeName = name;
      if (value === null) {  // 为空
        node.removeAttribute(attributeName); //  清除值
      } else {
        node.setAttribute(   // 设置
          attributeName,
          enableTrustedTypesIntegration ? (value: any) : '' + (value: any),
        );
      }
    }
    return;
  }
  const {mustUseProperty} = propertyInfo;
  if (mustUseProperty) {
    const {propertyName} = propertyInfo;
    if (value === null) {
      const {type} = propertyInfo;
      (node: any)[propertyName] = type === BOOLEAN ? false : '';
    } else {
      // Contrary to `setAttribute`, object properties are properly
      // `toString`ed by IE8/9.
      (node: any)[propertyName] = value;
    }
    return;
  }
  // The rest are treated as attributes with special cases.
  const {attributeName, attributeNamespace} = propertyInfo;
  if (value === null) {
    node.removeAttribute(attributeName);
  } else {
    const {type} = propertyInfo;
    let attributeValue;
    if (type === BOOLEAN || (type === OVERLOADED_BOOLEAN && value === true)) {
 
      attributeValue = '';
    } else {
      if (enableTrustedTypesIntegration) {
        attributeValue = (value: any);
      } else {
        attributeValue = '' + (value: any);
      }
      if (propertyInfo.sanitizeURL) {
        sanitizeURL(attributeValue.toString());
      }
    }
    if (attributeNamespace) {
      node.setAttributeNS(attributeNamespace, attributeName, attributeValue);
    } else {
      node.setAttribute(attributeName, attributeValue);
    }
  }
}
//  备注: 设置原生dom元素特性。详细细节不注释了。

// getPropertyInfo (23)

// 获取dom 节点的特性
export function getPropertyInfo(name: string): PropertyInfo | null {
  return properties.hasOwnProperty(name) ? properties[name] : null;
}
//  备注:获取dom 节点特定name的对应的attribute对象

//  shouldIgnoreAttribute
// 是否是该被忽略的特性
// url: src/react/packages/react-dom/src/shared/DOMProperty.js
export function shouldIgnoreAttribute(
  name: string,
  propertyInfo: PropertyInfo | null,
  isCustomComponentTag: boolean,
): boolean {
  // 特性兑现非空
  if (propertyInfo !== null) {  // 非空
    // export const RESERVED = 0;
    return propertyInfo.type === RESERVED;
  }
  // 是自己
  if (isCustomComponentTag) {
    return false;
  }
  // 具有isCustomComponentTag 数据
  if (
    name.length > 2 &&
    (name[0] === 'o' || name[0] === 'O') &&
    (name[1] === 'n' || name[1] === 'N')
  ) {
    return true;
  }
  return false;
}
//备注: 返回是否该被忽略的特性

// shouldRemoveAttributeWithWarning(24)

// 是否需要移除特性 
// ulr: src/react/packages/react-dom/src/shared/DOMProperty.js
export function shouldRemoveAttributeWithWarning(
  name: string,  // 名称
  value: mixed,  // 数据
  propertyInfo: PropertyInfo | null,
  isCustomComponentTag: boolean,
): boolean {
  // 不为空   // export const RESERVED = 0;
  if (propertyInfo !== null && propertyInfo.type === RESERVED) {
    return false;
  }
  switch (typeof value) {  // 
    case 'function':  // 函数
    // $FlowIssue symbol is perfectly valid here
    case 'symbol': // eslint-disable-line
      return true;
    case 'boolean': {
      if (isCustomComponentTag) {  // 自定义?
        return false;
      }
      if (propertyInfo !== null) { // 非空
        return !propertyInfo.acceptsBooleans;  // 接收数据为boolean, s实际不为boolean
      } else {
        const prefix = name.toLowerCase().slice(0, 5); // 前面5个字符
        return prefix !== 'data-' && prefix !== 'aria-';
      }
    }
    default:
      return false;
  }
}
// 备注:  value 为 函数或这boolean , 数据类型为boolean, 实际数据为非boolean。返回ture, 

// shouldRemoveAttribute(25)

// 是否是需要移除的特性
export function shouldRemoveAttribute(
  name: string,
  value: mixed,
  propertyInfo: PropertyInfo | null,
  isCustomComponentTag: boolean,
): boolean {
  // 值为空
  if (value === null || typeof value === 'undefined') {
    return true;
  }
  // 一些需要移除的特性
  if (
    shouldRemoveAttributeWithWarning(
      name,
      value,
      propertyInfo,
      isCustomComponentTag,
    )
  ) {
    return true;
  }
  // 自定义
  if (isCustomComponentTag) {
    return false;
  }
  // 非空
  if (propertyInfo !== null) {
   //  export const enableFilterEmptyStringAttributesDOM = false;
    if (enableFilterEmptyStringAttributesDOM) {  // false , 不执行
      if (propertyInfo.removeEmptyString && value === '') {
        // dev代码, 已删除
        return true;
      }
    }
    switch (propertyInfo.type) {
      case BOOLEAN:
        return !value;
      case OVERLOADED_BOOLEAN:
        return value === false;
      case NUMERIC:
        return isNaN(value);
      case POSITIVE_NUMERIC:
        return isNaN(value) || (value: any) < 1;
    }
  }
  return false;
}
// 备注: 判断是否需要删除的特性, 值为空,后者函数判断

// track(26)

// track 函数
// url: src/react/packages/react-dom/src/client/inputValueTracking.js
export function track(node: ElementWithValueTracker) {
//  初始时, node._valueTracker 不存在
  if (getTracker(node)) { // 如果存在数据
    return;
  }

 // 只执行一次
  node._valueTracker = trackValueOnNode(node);
}

// getTracker 函数 
function getTracker(node: ElementWithValueTracker) {
  return node._valueTracker;  // 返回_valueTracker
}
// 获取节点的_valueTracker 属性

/// trackValueOnNode  函数
function trackValueOnNode(node: any): ?ValueTracker {
  const valueField = isCheckable(node) ? 'checked' : 'value';
  const descriptor = Object.getOwnPropertyDescriptor(
    node.constructor.prototype,
    valueField,
  );

  let currentValue = '' + node[valueField];
  if (
    node.hasOwnProperty(valueField) ||
    typeof descriptor === 'undefined' ||
    typeof descriptor.get !== 'function' ||
    typeof descriptor.set !== 'function'
  ) {
    return;
  }
  const {get, set} = descriptor;
  Object.defineProperty(node, valueField, {
    configurable: true,
    get: function() {
      return get.call(this);
    },
    set: function(value) {
      currentValue = '' + value;
      set.call(this, value);
    },
  });
 
  Object.defineProperty(node, valueField, {
    enumerable: descriptor.enumerable,
  });

  const tracker = {
    getValue() {
      return currentValue;
    },
    setValue(value) {
      currentValue = '' + value;
    },
    stopTracking() {
      detachTracker(node);
      delete node[valueField];
    },
  };
  return tracker;
}
//  备注: 返回一个tracker, 什么用途? 

// ReactDOMInputPostMountWrapper(27)

// url: src/react/packages/react-dom/src/client/ReactDOMInput.js
import { 
  postMountWrapper as ReactDOMInputPostMountWrapper,
  
} from './ReactDOMInput';
export function postMountWrapper(
  element: Element,
  props: Object,
  isHydrating: boolean,
) {
  const node = ((element: any): InputWithWrapperState);
  if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {
    const type = props.type;
    const isButton = type === 'submit' || type === 'reset'; // 重置按钮或者提交
    if (isButton && (props.value === undefined || props.value === null)) {
      return; // 跳过
    }
   // 节点的初始值
    const initialValue = toString(node._wrapperState.initialValue);
    if (!isHydrating) {  // true
      if (disableInputAttributeSyncing) {
        const value = getToStringValue(props.value);
        if (value != null) {
          if (isButton || value !== node.value) {
            node.value = toString(value);
          }
        }
      } else {
        if (initialValue !== node.value) {
          node.value = initialValue;
        }
      }
    }

    if (disableInputAttributeSyncing) {
      const defaultValue = getToStringValue(props.defaultValue);
      if (defaultValue != null) {
        node.defaultValue = toString(defaultValue);
      }
    } else {
      node.defaultValue = initialValue;
    }
  }
  const name = node.name;
  if (name !== '') {
    node.name = '';
  }

  if (disableInputAttributeSyncing) {
    
    if (!isHydrating) {
      updateChecked(element, props);
    }
    if (props.hasOwnProperty('defaultChecked')) {
      node.defaultChecked = !node.defaultChecked;
      node.defaultChecked = !!props.defaultChecked;
    }
  } else {
 
    node.defaultChecked = !node.defaultChecked;
    node.defaultChecked = !!node._wrapperState.initialChecked;
  }

  if (name !== '') {
    node.name = name;
  }
}
//  备注: input类型的处理

// ReactDOMTextareaPostMountWrapper (28)

import {
    postMountWrapper as ReactDOMTextareaPostMountWrapper,
} from './ReactDOMTextarea';

// url: src/react/packages/react-dom/src/client/ReactDOMTextarea.js
export function postMountWrapper(element: Element, props: Object) {
  const node = ((element: any): TextAreaWithWrapperState);
  const textContent = node.textContent;
  if (textContent === node._wrapperState.initialValue) {
    if (textContent !== '' && textContent !== null) {
      node.value = textContent;
    }
  }
}
//  备注: 设置节点的数值?

// ReactDOMOptionPostMountWrapper(29)

import {
   postMountWrapper as ReactDOMOptionPostMountWrapper,
} from './ReactDOMOption';

// url: src/react/packages/react-dom/src/client/ReactDOMOption.js
export function postMountWrapper(element: Element, props: Object) {
  if (props.value != null) {
    element.setAttribute('value', toString(getToStringValue(props.value)));
  }
}
// 备注: 设置 option 类型的值
//  ReactDOMSelectPostMountWrapper
import {
  postMountWrapper as ReactDOMSelectPostMountWrapper,
} from './ReactDOMSelect';


// postMountWrapper
// url: src/react/packages/react-dom/src/client/ReactDOMSelect.js
export function postMountWrapper(element: Element, props: Object) {
  const node = ((element: any): SelectWithWrapperState);
  node.multiple = !!props.multiple;
  const value = props.value;
  if (value != null) {
    updateOptions(node, !!props.multiple, value, false);
  } else if (props.defaultValue != null) {
    updateOptions(node, !!props.multiple, props.defaultValue, true);
  }
}
//  备注: 设置options的数据

// updateOptions(30)

// 定义updateOptions
// url: src/react/packages/react-dom/src/client/ReactDOMSelect.js
function updateOptions(
  node: HTMLSelectElement,
  multiple: boolean,
  propValue: any,
  setDefaultSelected: boolean,
) {
  type IndexableHTMLOptionsCollection = HTMLOptionsCollection & {
    [key: number]: HTMLOptionElement,
    ...,
  };
  const options: IndexableHTMLOptionsCollection = node.options;

  if (multiple) {  // 可以多选
    const selectedValues = (propValue: Array<string>);
    const selectedValue = {};
    for (let i = 0; i < selectedValues.length; i++) {
      // Prefix to avoid chaos with special keys.
      selectedValue['$' + selectedValues[i]] = true;
    }
    for (let i = 0; i < options.length; i++) {
      const selected = selectedValue.hasOwnProperty('$' + options[i].value);
      if (options[i].selected !== selected) {
        options[i].selected = selected;
      }
      if (selected && setDefaultSelected) {
        options[i].defaultSelected = true;
      }
    }
  } else {
    // Do not set `select.value` as exact behavior isn't consistent across all
    // browsers for all cases.
    const selectedValue = toString(getToStringValue((propValue: any)));
    let defaultSelected = null;
    for (let i = 0; i < options.length; i++) {
      if (options[i].value === selectedValue) {
        options[i].selected = true;
        if (setDefaultSelected) {
          options[i].defaultSelected = true;
        }
        return;
      }
      if (defaultSelected === null && !options[i].disabled) {
        defaultSelected = options[i];
      }
    }
    if (defaultSelected !== null) {
      defaultSelected.selected = true;
    }
  }
}
// 备注: options数据更新

// trapClickOnNonInteractiveElement(31)

// trapClickOnNonInteractiveElement 定义
// url: src/react/packages/react-dom/src/client/ReactDOMComponent.js
export function trapClickOnNonInteractiveElement(node: HTMLElement) {
 node.onclick = noop;
}


function noop() {}
// 备注: 其他类型click的执行函数, 哪里绑定函数

// shouldAutoFocusHostComponent(32)

// 确认节点是否自动焦点聚焦
// url: src/react/packages/react-dom/src/client/ReactDOMHostConfig.js
function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
  switch (type) {
    case 'button':
    case 'input':
    case 'select':
    case 'textarea':
      return !!props.autoFocus;
  }
  return false;
}
// 备注: 确认当前节点是否被聚焦

// markUpdate(33)

// 当前节点有更新
// url: src/react/packages/react-reconciler/src/ReactFiberCompleteWork.old.js
function markUpdate(workInProgress: Fiber) {
 workInProgress.flags |= Update;
}
// 备注: 标示节点的更新, 在flags 上增加Update

// updateHostComponent(34)

// url: src/react/packages/react-reconciler/src/ReactFiberCompleteWork.old.js
updateHostComponent = function(
 current:updateHostComponent = function(
    current: Fiber,
    workInProgress: Fiber,
    type: Type,
    newProps: Props,
    rootContainerInstance: Container,
  ) {
  
    const oldProps = current.memoizedProps;
    // 属性没有更新
    if (oldProps === newProps) {  // 新旧props 没有更新
      return;
    }
    // dom 节点
    const instance: Instance = workInProgress.stateNode;
    const currentHostContext = getHostContext();
    // 处理更新的部分
    const updatePayload = prepareUpdate(  // 后取更新
      instance,
      type,
      oldProps,
      newProps,
      rootContainerInstance,
      currentHostContext,
    );
    // TODO: Type this specific to this type of component.
    workInProgress.updateQueue = (updatePayload: any);  // 获取更新队列
    // 具有更新的时候
    if (updatePayload) {  // 具有更新的时候
      markUpdate(workInProgress);  // workInProgress.flags |= Update;
    }
  };
// 备注: 原生dom节点的更新, 判断props 是否相等,相等则没有更新, 如果有更新, 将
// 更新添加到updateQueue, 并将节点flags 标示Update

// prepareUpdate(35)

// url: src/react/packages/react-dom/src/client/ReactDOMHostConfig.js
export function prepareUpdate(
  domElement: Instance,
  type: string,
  oldProps: Props,
  newProps: Props,
  rootContainerInstance: Container,
  hostContext: HostContext,
): null | Array<mixed> {
  //  dev 代码, 已省略
  // dom 节点的diff 算法
  return diffProperties(
    domElement,  // dom 节点
    type,   //  节点
    oldProps,  // 旧的属性props
    newProps,  // 新的属性props
    rootContainerInstance,  // div#root
  );
}
// 备注: 通过返回执行diffProperties 获取dom节点的真正更新。

// diffProperties(37)

// 计算节点的属性差异
export function diffProperties(
  domElement: Element,
  tag: string,
  lastRawProps: Object,
  nextRawProps: Object,
  rootContainerElement: Element | Document,
): null | Array<mixed> {
  // dev代码,已省略
  // 初始值为空
  let updatePayload: null | Array<any> = null; // 初始值为null
  let lastProps: Object;
  let nextProps: Object;
  // 获取
  switch (tag) {
    case 'input':
      lastProps = ReactDOMInputGetHostProps(domElement, lastRawProps); // 旧的props
      nextProps = ReactDOMInputGetHostProps(domElement, nextRawProps);
      updatePayload = [];  // 设置为空数组
      break;
    case 'option':
      lastProps = ReactDOMOptionGetHostProps(domElement, lastRawProps);
      nextProps = ReactDOMOptionGetHostProps(domElement, nextRawProps);
      updatePayload = [];  // 设置为空数组
      break;
    case 'select':
      lastProps = ReactDOMSelectGetHostProps(domElement, lastRawProps);
      nextProps = ReactDOMSelectGetHostProps(domElement, nextRawProps);
      updatePayload = [];  // 设置为空数组
      break;
    case 'textarea':
      lastProps = ReactDOMTextareaGetHostProps(domElement, lastRawProps);
      nextProps = ReactDOMTextareaGetHostProps(domElement, nextRawProps);
      updatePayload = [];  // 设置为空数组
      break;
    default:
      lastProps = lastRawProps;
      nextProps = nextRawProps;
      if (
        typeof lastProps.onClick !== 'function' &&
        typeof nextProps.onClick === 'function'
      ) {
        // 空函数
        trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
      }
      break;
  }
  assertValidProps(tag, nextProps);  // props 校验
  let propKey;
  let styleName;
  let styleUpdates = null; // 样式的更新
// 循环lastProps
  for (propKey in lastProps) {  // 遍历旧的props
    // 删除的属性的遍历, 这里只记录,旧的有,新的没有的数据
    if (
      nextProps.hasOwnProperty(propKey) ||  // 新的有
      !lastProps.hasOwnProperty(propKey) ||  // 旧的没有
      lastProps[propKey] == null
    ) {
      continue;
    }
    // key  : style 
    if (propKey === STYLE) {  // style
      const lastStyle = lastProps[propKey];
      for (styleName in lastStyle) {  // 遍历旧的style 
        if (lastStyle.hasOwnProperty(styleName)) {
          if (!styleUpdates) {
            styleUpdates = {};
          }
          styleUpdates[styleName] = '';  //  删除的
        }  // style 的处理为 {styleName1: ''}  // 都在一个对象
      }
    } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
      // Noop. This is handled by the clear text mechanism.
    } else if (
      propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
      propKey === SUPPRESS_HYDRATION_WARNING
    ) {
      // Noop
    } else if (propKey === AUTOFOCUS) {
      // Noop. It doesn't work on updates anyway.
    } else if (registrationNameDependencies.hasOwnProperty(propKey)) {
   //
      if (!updatePayload) {
        updatePayload = [];
      }
    } else {
    
      // 记录所有需要删除的属性
      (updatePayload = updatePayload || []).push(propKey, null);
    }
  }
  // 遍历新的属性
  for (propKey in nextProps) {
    // 属性值
    const nextProp = nextProps[propKey];
    // 
    const lastProp = lastProps != null ? lastProps[propKey] : undefined;
    if (
      !nextProps.hasOwnProperty(propKey) ||  // 原型上的
      nextProp === lastProp || // 相等
      (nextProp == null && lastProp == null)  // 都为空
    ) {
      continue;
    }
    if (propKey === STYLE) { // tyle 
      // dev代码,已省略
      if (lastProp) {  // 旧的存在
        // Unset styles on `lastProp` but not on `nextProp`.
        for (styleName in lastProp) {
          if (
            lastProp.hasOwnProperty(styleName) &&
            (!nextProp || !nextProp.hasOwnProperty(styleName))
          ) {
            // 初始化
            if (!styleUpdates) {
              styleUpdates = {};
            }
            styleUpdates[styleName] = '';
          }
        }
        // Update styles that changed since `lastProp`.
        for (styleName in nextProp) {
          if (
            nextProp.hasOwnProperty(styleName) &&
            lastProp[styleName] !== nextProp[styleName]
          ) {
            if (!styleUpdates) {
              styleUpdates = {};
            }
            styleUpdates[styleName] = nextProp[styleName];
          }
        }
      } else {
        // 旧的不存在
        // Relies on `updateStylesByID` not mutating `styleUpdates`.
        if (!styleUpdates) {   // 旧的style 没有
          if (!updatePayload) {
            updatePayload = [];
          }
          updatePayload.push(propKey, styleUpdates); // 
        }
        styleUpdates = nextProp;  // 属性更新
      }
    } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
      // 属性是否变化
      const nextHtml = nextProp ? nextProp[HTML] : undefined;
      const lastHtml = lastProp ? lastProp[HTML] : undefined;
      if (nextHtml != null) {
        if (lastHtml !== nextHtml) {
          (updatePayload = updatePayload || []).push(propKey, nextHtml);
        }
      } else {
        // TODO: It might be too late to clear this if we have children
        // inserted already.
      }
    } else if (propKey === CHILDREN) {
      // children 
      if (typeof nextProp === 'string' || typeof nextProp === 'number') {
        (updatePayload = updatePayload || []).push(propKey, '' + nextProp);
      }
    } else if (
      propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
      propKey === SUPPRESS_HYDRATION_WARNING
    ) {
      // Noop
    } else if (registrationNameDependencies.hasOwnProperty(propKey)) {
      if (nextProp != null) {
       // dev代码,已省略
        if (!enableEagerRootListeners) {
          ensureListeningTo(rootContainerElement, propKey, domElement);
        } else if (propKey === 'onScroll') {
          listenToNonDelegatedEvent('scroll', domElement);
        }
      }
      if (!updatePayload && lastProp !== nextProp) {
        
        updatePayload = [];
      }
    } else if (
      typeof nextProp === 'object' &&
      nextProp !== null &&
      nextProp.$$typeof === REACT_OPAQUE_ID_TYPE
    ) {
    
      nextProp.toString();
    } else {
      // 新增的
     
      (updatePayload = updatePayload || []).push(propKey, nextProp);
    }
  }
  if (styleUpdates) {
    if (__DEV__) {
      validateShorthandPropertyCollisionInDev(styleUpdates, nextProps[STYLE]);
    }
    (updatePayload = updatePayload || []).push(STYLE, styleUpdates);
  }
  return updatePayload;
}
// dom 节点的属性diff
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值