h.js

  • wtf-is-jsx

    • function render(vnode) {  
        	// Strings just convert to #text Nodes:
          if (vnode.split) return document.createTextNode(vnode);
      
          // create a DOM element with the nodeName of our VDOM element:
          let n = document.createElement(vnode.nodeName);
      
          // copy attributes onto the new node:
          let a = vnode.attributes || {};
          Object.keys(a).forEach( k= > n.setAttribute(k, a[k]) );
      
          // render (build) and then append child nodes:
          (vnode.children || []).forEach( c= > n.appendChild(render(c)) );
      
          return n;
      }
      
      var vnode = {
        	nodeName: "div".attributes: {
          	"id": "fei"
        	},
        	children: ["Hello!"]
      }
      
      render(vnode) =======> <div id="fei">Hello!</div>
      Copy the code
  • Creates a VNode (virtual DOM element). A tree of VNodes can be used as a lightweight representation

    of the structure of a DOM tree. This structure can be realized by recursively comparing it against

    the current actual DOM structure, and applying only the differences.

  • h(nodeName, attributes)

    • Accept nodeName and Attributes, and the remaining parameters are pushed onto the stack

    • const stack = []
      for (i = arguments.length; i-- > 2;) { stack.push(arguments[i]);
      }
      Copy the code
    • NodeName: indicates the HTML tag. Div, a, span… .

constants.js

  • // render modes
    
    / / not render
    export const NO_RENDER = 0;
    Render / / synchronization
    export const SYNC_RENDER = 1;
    / / render
    export const FORCE_RENDER = 2;
    Asynchronous render / /
    export const ASYNC_RENDER = 3;
    
    
    export const ATTR_KEY = '__preactattr_';
    Copy the code

component.js

  • export function Component(props, context) {
        After calling this.setstate (), mark _dirty = true. At the end of each event loop, check that all components marked _dirty are redrawn.
    	this._dirty = true;
    	this.context = context;
    	this.props = props;
    	this.state = this.state || {};
    }
    Copy the code
  • SetState (state, cb) : State – > enqueueRender used to update components

  • ForceUpdate (CB): Rerender components immediately — > renderComponent

  • Render: vNode that returns the render content of the component

dom / index.js

  • createNode: document.createElement(nodeName)
  • removeNode: parentNode.removeChild(node)
  • SetAccessor Sets node properties
    • ClassName, key, ref, style, dangerouslySetInnerHTML…
    • OnXxxx: Node. addEventListener(Name, eventProxy, useCapture) hook function

vdom

index.js
  • isSameNodeType(node, vnode, hydrating)
  • isNamedNode(node, nodeName)
  • getNodeProps(vnode)
component.js
  • setComponentProps
  • renderComponent
    • component.shouldComponentUpdate
    • component.componentWillUpdate
    • component.render
    • component.componentDidUpdate
    • options.afterUpdate
    • component._renderCallbacks
    • flushMounts()
  • buildComponentFromVNode
    • Apply the Component referenced by a VNode to the DOM.
  • unmountComponent
    • Remove a component from the DOM and recycle it
diff.js
  • Apply differences in a given vnode (and it’s deep children) to a real DOM Node.

  • flushMounts()

  • diff(dom, vnode, context, mountAll, parent, componentRoot)

  • // DOM: the previously unupdated real DOM corresponding to the vNode
    // vnode: virtual DOM to render
    // parent: the parent node to which you want to mount the virtual DOM
    export function diff(dom, vnode, context, mountAll, parent, componentRoot) {
    	// diffLevel having been 0 here indicates initial entry into the diff (not a subdiff)
    	if(! diffLevel++) {// when first starting the diff, check if we're diffing an SVG or within an SVGisSvgMode = parent! =null&& parent.ownerSVGElement! = =undefined;
    		// hydration is indicated by the existing element to be diffed not having a prop cachehydrating = dom! =null && !(ATTR_KEY in dom);
    	}
    
    	let ret = idiff(dom, vnode, context, mountAll, componentRoot);
    	
        // append the element if its a new parent
    	if(parent && ret.parentNode! ==parent) parent.appendChild(ret);// diffLevel being reduced to 0 means we're exiting the diff
    	if(! --diffLevel) { hydrating =false;
            // invoke queued componentDidMount lifecycle methods
    		if(! componentRoot) flushMounts(); }return ret;
    }
    Copy the code
  • idiff(dom, vnode, context, mountAll, componentRoot)

    • Internal implementation of diff algorithm

    • function idiff(dom, vnode, context, mountAll, componentRoot) {
          // An empty node renders an empty text node
      	if (vnode==null || typeof vnode==='boolean') vnode = ' ';
          
      	// VNode is a node of simple types such as String and Number
          if(dom === 'text') {
              // dom is text, update if it's already a text node:
              dom.nodeValue = vnode;
          } else {
                  // dom is not text, replace it with one and recycle the old Element
            	document.createTextNode(vnode);
      	    dom.parentNode.replaceChild(out, dom);
          	recollectNodeTree(dom, true);   
          }
          
          / / VNode for component
          // DOM does not exist or has an incorrect type
          // Dom and vnode names are different
          if(! dom || ! isNamedNode(dom, vnodeName)) { out = createNode(vnodeName, isSvgMode);if (dom) {
      			// move children into the replacement node
      			while (dom.firstChild) out.appendChild(dom.firstChild);
      
      			// if the previous Element was mounted into the DOM, replace it inline
      			if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
      
      			// recycle the old element (skips non-Element node types)
      			recollectNodeTree(dom, true); }}// DOM exists and has the same name as vnode
       	let fc = out.firstChild,
      		props = out[ATTR_KEY],
      		vchildren = vnode.children;
      
      	if (props == null) {
      		props = out[ATTR_KEY] = {};
      		for (leta=out.attributes, i=a.length; i--; ) props[a[i].name] = a[i].value; }...// Vchildren has only one direct assignment
          if(vchildren.length===1) fc.nodeValue = vchildren[0]
          // else 
          innerDiffNode()
      }
      
      // Important, watch this a few times
      function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
      	let originalChildren = dom.childNodes,
      		children = [],
      		keyed = {},
      		keyedLen = 0,
      		min = 0,
      		len = originalChildren.length,
      		childrenLen = 0,
      		vlen = vchildren ? vchildren.length : 0,
      		j, c, f, vchild, child;
      
      	// Create a child element with key and a Map without child elements
          Keyed [key] = child; /* preact [key] = child; Child.nodevalue.trim (); children[childrenLen++] = child * /
      	if(len! = =0) {
      		for (let i=0; i<len; i++) {
      			let child = originalChildren[i],
      				props = child[ATTR_KEY],
      				key = vlen && props ? child._component ? child._component.__key : props.key : null;
      			if(key! =null) {
      				keyedLen++;
      				keyed[key] = child;
      			}
      			else if(props || (child.splitText! = =undefined ? (isHydrating ? child.nodeValue.trim() : true) : isHydrating)) { children[childrenLen++] = child; }}}/ / traverse vnode
      	if(vlen! = =0) {
      		for (let i=0; i<vlen; i++) {
      			vchild = vchildren[i];
      			child = null;
      
      			// Use key to find nodes
      			let key = vchild.key;
                 	/ / have the key
      			if(key! =null) {
      				if(keyedLen && keyed[key]! = =undefined) {
                          // Find the dom element in keyed and delete the element in keyed
      					child = keyed[key];
      					keyed[key] = undefined; keyedLen--; }}// Find nodes of the same type from existing child nodes
      			else if(! child && min<childrenLen) {for (j=min; j<childrenLen; j++) {
                          // isSameNodeType looks for nodes of the same type as the element
      					if(children[j]! = =undefined && isSameNodeType(c = children[j], vchild, isHydrating)) {
                              // If there are nodes of the same type, delete them in children
      						child = c;
      						children[j] = undefined;
                              // Narrow down the search
      						if (j===childrenLen- 1) childrenLen--;
      						if (j===min) min++;
      						break; }}}/ / recursive idiff
      			// morph the matched/found/created DOM child to match vchild (deep)
      			child = idiff(child, vchild, context, mountAll);
      
      			f = originalChildren[i];
                  // This dom corresponds to the corresponding DOM in the original DOM
      			if(child && child! ==dom && child! ==f) {if (f==null) {
                          // Add it before the corresponding location
      					dom.appendChild(child);
      				}
      				else if (child===f.nextSibling) {
                          // Remove the current real DOM
      					removeNode(f);
      				}
      				else {
                          // Add to the parent nodedom.insertBefore(child, f); }}}}Copy the code
    • // DOM event is triggered
      function diffAttributes(dom, attrs, old) {
      	let name;
      
      	// = undefined, remove attributes that are not in vNode
      	for (name in old) {
      		if(! (attrs && attrs[name]! =null) && old[name]! =null) {
      			setAccessor(dom, name, old[name], old[name] = undefined, isSvgMode); }}// add new & update changed attributes
      	for (name in attrs) {
      		if(name! = ='children'&& name! = ='innerHTML'&& (! (nameinold) || attrs[name]! ==(name==='value' || name==='checked'? dom[name] : old[name]))) { setAccessor(dom, name, old[name], old[name] = attrs[name], isSvgMode); }}Copy the code
component-recycler.js
  • const components = {}

    • Retains a pool of Components for re-use, keyed on component name.
  • collectComponent(component)

    • Reclaim a component for later re-use by the recycler
    • component.constructor.name;
  • createComponent(Ctor, props, context)

    • Creating component instances (PFC’s and Classful Components)

    • Pure Function Component (RFC) Pure Function Component

    • // Fetch the instance of the same class from the pool created, and then fetch the instance rendered before that instance (nextBase)
      // Purpose: Render only the current DOM, optimize rendering
      if (list) {
          for (let i=list.length; i--; ) {
              if (list[i].constructor===Ctor) {
                  // Assign to the nextBase property of our newly created component instance
                  inst.nextBase = list[i].nextBase;
                  list.splice(i, 1);
                  break; }}}Copy the code