Vue and react will be able to use JSX and source code summary

Time:2021-1-24

background

Front end students should know that react and Vue are the most popular frameworks or libraries in China. There are many similarities between them

  • Using virtual DOM
  • It provides reactive and composable view components
  • Focus on the core library, and give other functions such as routing and global state management to the relevant library

But it’s different,VueIs a progressive JavaScript framework, characterized by easy to use, flexible, efficient.ReactIs a JavaScript library for building user interface, characterized by declarative UI writing, componentization, one-time learning, writing everywhere. Of course, here is not the difference between the two, just to lead to a more intuitive difference in the development process, that is, the way views are written.


Correct posture of JSX in react and Vue

In the project of react, everything is JavaScript. HTML can be written with JSX, but in fact, there is no relationship between JSX and HTML. JSX is actually a kind of syntax sugar, which will eventually be converted into JavaScript code. But the advantages of JSX are obvious, such as:

  • You can use JavaScript to build your view page.

    //The first letter of the variable name saved by the component must be uppercase, otherwise it cannot be rendered successfully
     //React DOM uses camelCase naming to define attribute names instead of HTML attribute names
     //Use temporary variables, JS's own process control, and directly reference the values in the current JS scope.
     const demoReact.createClass({
       render: function() {
         var dataArr = [1,2,3,4],
             jsxDomList = [];
          //Temporary variable 
         dataArr.forEach(function(item, index) {
            //JS control
            if(index < 4){
               //Class needs to be changed to classname
               //Only expressions (logical operators (|, & & etc.) and ternary operators can be written between the braces, not statements such as judgment
              jsxDomList.push(<li className="item">{item}</li>);
            }
         });
         //Event binding inline style
         return (<ul 
             onClick={this.handlerClick} 
           style={{width:30,height:30,backgroundColor:'red'}>
               {jsxDomList}
           </ul>);
       } 
       handlerClick: function() {
           Alert ('click ');
       }
    });
    ReactDOM.render(<HelloMessage name="John" />,document.getElementById('example'));
  • Development tools support JSX better than other available toolsVueMore advanced templates (such as linking, type checking, automatic completion of editor) (strong ecological support)

Vue recommends using template to create our HTML. I believe that 99% of the front ends in daily development use this method. In fact, Vue also provides rendering functions that support JSX syntax. But the grammar is different.

If the render function in the Vue option exists, the Vue constructor will not compile the render function from the HTML template extracted from the template option or the mount element specified by the El option.

In     react, all data passed between father and son are attributes, that is, all data are mounted in theprops(style, classname, children, value, onchange, etc.). Vue has three attributes: component attribute props, HTML attribute attrs, DOM attribute domprops.

  • React
var reactElement = ReactElement.createElement(
      'demo ', // tag name string / reactclass
      {
      id: "title",
      className: "bg",
      style: {
        color: 'red'
      }
    }// {attribute value of element is object} or null
      Sth... // [element's child node] the child node array may not be transferred
)
  • Vue2.0
return createElement('div', {
  //With ` V- bind:class `The API of is the same
  'class': {
    foo: true,
  },

  //With ` V- bind:style `The API of is the same,
  //Accepts a string, an object, or an array of objects
  style: {
    color: 'blue',
    fontSize: '14px'
  },

  //Common HTML features
  attrs: {
    id: 'foo'
  },

  //Component prop
  props: {
    myProp: 'bar'
  },
  //DOM properties
  domProps: {
    innerHTML: 'eg'
  },
  //The event listener is in the 'on' attribute,
  //But no longer support such as ` v-on: keyup.enter `Such a decorator.
  //You need to check the keycode manually in the handler.
  on: {
    click: this.clickHandler
  },

  //It is only used for components to listen for native events, not for internal use of components
  //Event triggered by ` VM. $emit '.
  nativeOn: {
    click: this.nativeClickHandler
  },

  //Custom instructions. Note that you can't edit the 'oldvalue' in 'binding'`
  //Assignment, because Vue has automatically synchronized for you
  //For example, common permission management instructions
  directives: [
    {
      name: 'permissions',
      value: {
        currentPermissions:
          'download_csv'
      }
    }
  ],

  //The format of the scope slot is
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },

  //If the component is a child of another component, specify a name for the slot
  slot: 'name-of-slot',
  //Other special top level properties
  key: 'myKey',
  ref: 'myRef',
  //If you apply the same ref name to multiple elements in the render function,
  //So`$ refs.myRef `It becomes an array.
  refInFor: true
})
  • Vue3.0
//Vue3.0 official example
const app = Vue.createApp({})
app.component('anchored-heading', {
  render() {
    const { h } = Vue
    return h(
      'h' +  this.level , // tag name string
      {}, // props/attributes
      this.$ slots.default () // the array of child nodes may not be transferred
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})
//main.js
app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})
//component
setup(props, { slots, emit }) {
    //Response value
    const count = ref(1)
    //Use instructions
    const vDemo = resolveDirective('demo')
    return ()=>{
      const dom = h('a',{
        class: ['wrap'],
        style: {
          zIndex: count.value,
        },
        onClick: ()=>{
          console.log ('click 1 ');
        },
        onMouseover: ()=>{
          console.log ('mouseover ');
        },
        onUpdate:()=>{
          console.log('update');
        },
        //Normal HTML features
        href:'www.baidu.com',
        key: 'myKey',
        ref: 'myRef'
      },[
        h('span',null,123)
      ])
      console.log(dom);
      return withDirectives(dom,[[vDemo, { color: 'white', text: 'hello!' }]])
    }
  },

Console printing

Vue and react will be able to use JSX and source code summary

Create element source code of react

function createElement(type, config, children) {       
      var propName;
      //Extract reserved name
      var props = {};
      var key = null;
      var ref = null;
      var self = null;
      var source = null;
      //When the attribute of the tag is not empty, it means that the tag has special treatment of attribute value: assign key and ref to separate variables
      if (config != null) {
        //There is a reasonable Ref
        if (hasValidRef(config)) {
          ref = config.ref;
        }
        //There is a reasonable key 
        if (hasValidKey(config)) {
          key = '' + config.key;
        }

        self = config.__self === undefined ? null : config.__self;
        source = config.__source === undefined ? null : config.__source;
        //The remaining attribute in config is not a native attribute (reserved)_ Properties of props object) are added to the new props object
        for (propName in config) {
          if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
            //Config removes the key / ref and puts it into the props object
            props[propName] = config[propName]; 
          }
        }
      }
      //Number of child elements (the third parameter and subsequent parameters are child element siblings)
      var childrenLength = arguments.length - 2; 
      if (childrenLength === 1) {
        props.children = children;
      } else if (childrenLength > 1) {
        //Declare an array
        var childArray = Array(childrenLength); 
        //Push children into the array in turn
        for (var i = 0; i < childrenLength; i++) {
          childArray[i] = arguments[i + 2];
        }

        {
          //Freezing array returns the original childarray and cannot be modified to prevent someone from modifying the core object of the library. Freezing objects greatly improves performance
          if (Object.freeze) {
            Object.freeze(childArray);
          }
        }
        //The parent component is passed internally this.props.children Gets the value of the subcomponent
        props.children = childArray; 
      } 

      //Setting default values for subcomponents is generally for components      
      //class com extends  React.component  be com.defaultProps Gets the static method of the current component itself 
      if (type && type.defaultProps) { 
         //If there is a default default props in the current component, the default content of the current component is defined in the default props
        var defaultProps = type.defaultProps; 

        for (propName in defaultProps) { 
          if (props[propName] === undefined) { 
            //If the corresponding value in the parent component is undefinde, the default value is assigned to props as the property of props
            props[propName] = defaultProps[propName];
          }
        }
      }

      {
        //Once ref or key exists
        if (key || ref) {
          //If type is a component
          var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
          if (key) {
            defineKeyPropWarningGetter(props, displayName);
          }

          if (ref) {
            defineRefPropWarningGetter(props, displayName);
          }
        }
      }

      //props:
      //1. The property value of config
       //2. Properties of children (string / array)
       //3. Attribute value of default
      return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
    }

The implementation of vue3.0 and the source code of JSX

Vue and react will be able to use JSX and source code summary

function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null, isBlockNode = false) {
    //Illegal type passed in
    if (!type || type === NULL_DYNAMIC_COMPONENT) {
        if ( !type) {
            warn(`Invalid vnode type when creating vnode: ${type}.`);
        }
        type = Comment;
    }
    if (isVNode(type)) {
        //Createvnode receives the existing vnode, for example: < component: is = "vnode" / >
        //Make sure refs are merged during cloning, not overridden
        const cloned = cloneVNode(type, props, true /* mergeRef: true */);
        if (children) {
            normalizeChildren(cloned, children);
        }
        return cloned;
    }
    //Class component standardization
    if (isClassComponent(type)) {
        type = type.__vccOpts;
    }
    //Class & style processing
    if (props) {
        //For a reactive or proxy object, we need to clone it to enable it
        if (reactivity.isProxy(props) || InternalObjectKey in props) {
            props = shared.extend({}, props);
        }
        let { class: klass, style } = props;
        if (klass && !shared.isString(klass)) {
            props.class = shared.normalizeClass(klass);
        }
        if (shared.isObject(style)) {
            //Reactive objects need to be cloned because they can mutate
            if (reactivity.isProxy(style) && !shared.isArray(style)) {
                style = shared.extend({}, style);
            }
            props.style = shared.normalizeStyle(style);
        }
    }
    //Encode vnode type information
    const shapeFlag = shared.isString(type)
        ? 1 /* ELEMENT */
        :  isSuspense(type)
            ? 128 /* SUSPENSE */
            : isTeleport(type)
                ? 64 /* TELEPORT */
                : shared.isObject(type)
                    ? 4 /* STATEFUL_COMPONENT */
                    : shared.isFunction(type)
                        ? 2 /* FUNCTIONAL_COMPONENT */
                        : 0;
    if ( shapeFlag & 4 /* STATEFUL_COMPONENT */ && reactivity.isProxy(type)) {
        type = reactivity.toRaw(type);
        warn(`Vue received a Component which was made a reactive object. This can ` +
            `lead to unnecessary performance overhead, and should be avoided by ` +
            `marking the component with \`markRaw\` or using \`shallowRef\` ` +
            `instead of \`ref\`.`, `\nComponent that was made reactive: `, type);
    }
    //Value contained in vnode
    const vnode = {
        __v_isVNode: true,
        ["__v_skip" /* SKIP */]: true,
        type,
        props,
        key: props && normalizeKey(props),
        ref: props && normalizeRef(props),
        scopeId: currentScopeId,
        children: null,
        component: null,
        suspense: null,
        ssContent: null,
        ssFallback: null,
        dirs: null,
        transition: null,
        el: null,
        anchor: null,
        target: null,
        targetAnchor: null,
        staticCount: 0,
        shapeFlag,
        patchFlag,
        dynamicProps,
        dynamicChildren: null,
        appContext: null
    };
    //The key value cannot be Nan
    if ( vnode.key !== vnode.key) {
        warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type);
    }
    normalizeChildren(vnode, children);
    // normalize suspense children
    if ( shapeFlag & 128 /* SUSPENSE */) {
        const { content, fallback } = normalizeSuspenseChildren(vnode);
        vnode.ssContent = content;
        vnode.ssFallback = fallback;
    }
    if (shouldTrack > 0 &&
        //Avoid block nodes tracking themselves
        !isBlockNode &&
        //There is a current parent block
        currentBlock &&
        //The component node should always be patched, because even if the component does not need to be updated, it needs to persist the instance to the next vnode so that it can be unloaded correctly later.
        (patchFlag > 0 || shapeFlag & 6 /* COMPONENT */) &&
        //The event flag is just for the purpose of hydration
        //If it is the only flag, vnode should not be considered dynamic because of the handler cache
        patchFlag !== 32 /* HYDRATE_EVENTS */) {
        currentBlock.push(vnode);
    }

last

   in Vue, there are many scenarios in which JSX is used. For example, most UI frameworks have table rendering. If the framework passes in object data and then uses JSX to render, its flexibility will be very high. such asView UI, the original iViewAnd no matter react or Vue is to improve the productivity of developers, no one is good or bad. Only in different production environment, who is more suitable.

   if you want to learn more about vue3.0, you can check it outVue3.0 learning

Last sentence, like the support!