preface

JSX = react.createElement (); JSX = react.createElement (); This article is a summary of the author in the process of learning and exploring.

What is the JSX

JSX stands for JavaScript XML, essentially reac.createElement () syntax sugar. You can compile to JS from Babel or TypeScript

JSX usage flow

To React, for instance

let root = document.getElementById('root')
function App(){
    return(<h1>Hello, world!</h1>)
}
ReactDOM.render(<App/>,root);
Copy the code

JSX translation via Babel

"use strict";
let root = document.getElementById('root');
function App() {
  return /*#__PURE__*/React.createElement("h1".null."Hello, world!");
}
ReactDOM.render( /*#__PURE__*/React.createElement(App, null), root);
Copy the code

You can see that the parser parses JSX to react. createElement, which creates the Virtual DOM and mounts it as a real DOM node via reactdom.render.

VDOM

The Virtual DOM is the Virtual DOM node. It simulates nodes in the DOM through JS objects and then renders them as real DOM nodes using a specific render method. Changes in the virtual DOM are resolved through the diff algorithm to trigger re-rendering. The virtual DOM itself is a normal JavaScript object that contains attributes tag, props, and children. Traditional DOM objects contain too many Attributes and are therefore inefficient to operate.

Implement a VDOM generator of your own h()

Start by defining the react.createElement () function called in the transformed code, which is also called h().

The createElement function defined in most frameworks is alias h()

function h(nodeName, attributes, ... args) {
      letchildren = args.length ? [].concat(... args) :null;
      return { nodeName, attributes, children };
}
Copy the code

The h() method outputs a nested tree object, also known as a VDOM object

{
  nodeName: "div".attributes: {
    "id": "hello"
  },
  children: ["Hello!"]}Copy the code

You also need a render() to convert the VDOM to the DOM node

function render(vnode) {
    // Create a text node if vnode is a string
    if (typeof(vnode)=='string') return document.createTextNode(vnode);
    
    // Create a node based on the vNode name
    let n = document.createElement(vnode.nodeName);
    
    // setAttribute for the new node
    let a = vnode.attributes || {};
    Object.keys(a).forEach( k= > n.setAttribute(k, a[k]) );
    
    // Mount each node to its parent recursively
    (vnode.children || []).forEach( c= > n.appendChild(render(c)) );
    return n;
}
Copy the code

Last call document. The body. The appendChild (render (< hello > “hello!” )); Insert the transformed DOM into the document.

Take a look at h() implementations of other frameworks

Omi

Omi is a front-end cross-frame framework based on WebComponent +JSX

export function h(nodeName, attributes) {
  let children = [],
    lastSimple,
    child,
    simple,
    i
    
  for (i = arguments.length; i-- > 2;) { stack.push(arguments[i])
  }
  if(attributes && attributes.children ! =null) {
    if(! stack.length) stack.push(attributes.children)delete attributes.children
  }
  
  while (stack.length) {
    if((child = stack.pop()) && child.pop ! = =undefined) {
      for (i = child.length; i--; ) stack.push(child[i])
    } else {
      if (typeof child === 'boolean') child = null
      
      if ((simple = typeofnodeName ! = ='function')) {
        if (child == null) child = ' '
        else if (typeof child === 'number') child = String(child)
        else if (typeofchild ! = ='string') simple = false
      }

      if (simple && lastSimple) {
        children[children.length - 1] += child
      } else if (children.length === 0) {
        children = [child]
      } else {
        children.push(child)
      }

      lastSimple = simple
    }
  }

  if (nodeName === Fragment) {
    return children
  }

  const p = {
    nodeName,
    children,
    attributes: attributes == null ? undefined : attributes,
    key: attributes == null ? undefined : attributes.key
  }

  // if a "vnode hook" is defined, pass every created VNode to it
  if(options.vnode ! = =undefined) options.vnode(p)

  return p
}
Copy the code

fre

Fre is a front-end framework based on Fiber architecture, the source code is written very wonderful worth learning

export const h = (type, props: any, ... kids) = > {
  props = props || {}
  
  const c = arrayfy(props.children || kids)
  
  kids = flat(c).filter((i) = >i ! =null)
  
  if (kids.length) props.children = kids.length === 1 ? kids[0] : kids
  let key = props.key || null,
    ref = props.ref || null
  
  delete props.key
  delete props.ref
  return createVnode(type, props, key, ref)
}

export const arrayfy = (arr) = >(! arr ? [] : isArr(arr) ? arr : [arr])const flat = (arr) = >[].concat( ... arr.map((v) = >
      isArr(v) ? [].concat(flat(v)) : isStr(v) ? createText(v) : v
    )
  )

export const createVnode = (type, props, key, ref) = > ({
  type,
  props,
  key,
  ref
})

export const createText = (vnode: any) = >
  ({ type: "".props: { nodeValue: vnode + ""}}as FreElement)

export function Fragment(props) {
  return props.children
}

export const isArr = Array.isArray
Copy the code

Vue3

export function h(type: any, propsOrChildren? : any, children? : any) :VNode {
  const l = arguments.length
  if (l === 2) {
    if(isObject(propsOrChildren) && ! isArray(propsOrChildren)) {if (isVNode(propsOrChildren)) {
        return createVNode(type, null, [propsOrChildren])
      }
      return createVNode(type, propsOrChildren)
    } else {
      return createVNode(type, null, propsOrChildren)
    }
  } else {
    if (l > 3) {
      children = Array.prototype.slice.call(arguments.2)}else if (l === 3 && isVNode(children)) {
      children = [children]
    }
    return createVNode(type, propsOrChildren, children)
  }
}
Copy the code

conclusion

In general, the implementation of H () is a key point of using JSX. Most frameworks have their own specific implementation, but the purpose is the same, they are all generated virtual DOM. The core difference of most frameworks lies in the tracking of virtual DOM changes, that is, the Diff algorithm. If there are mistakes, please criticize and correct them.