As a veteran vUE rookie player, I recently changed my react stack and suddenly changed my toys. I still felt like I was in the game, so I started a series of entertainment packages

I don’t use a ready-made API

Let’s take a look at some of the common vue apis:

  • beforeCreate
  • created
  • mounted
  • unmounted
  • watch
  • computed

Ok, just for these several commonly used play;

In order to implement react, we need to know if react is ready to use. After all, we can write more bugs in the remaining time. First can is componentDidMount corresponding, followed by componentWillUnmount, finally is half componentDidUpdate didn’t understand, good for the rest of the fiddle, the mapping table is as follows:

const API = {
  beforeCreate: 'constructor'.mounted: 'componentDidMount'.unmounted: 'componentWillUnmount'.beforeUpdate: 'shouldComponentUpdate'.watch: 'componentDidUpdate'.didCatch: 'componentDidCatch'};Copy the code

An appetizer

I’m going to write a few little functions that I can use, because I’m not doing anything

function $defineProperty(target, key, descriptor) {
  return Object.defineProperty(target, key, descriptor);
}

function getKeys(target) {
  return Object.keys(target);
}

function type(obj, type) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLocaleLowerCase() === type;
}

['String'.'Object'.'Function'.'Array'].forEach((key) = > {
  type['is' + key] = function(target) {
    return type(target, key.toLocaleLowerCase());
  };
});
Copy the code

Have some tea

First, review the vue lifecycle and various execution rules within mixins;

  • BeforeCreate -> Created -> create -> beforeMount -> Create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create -> create Mounted (parent)
  • The Data execution component precedes mixins
  • The lifecycle executes mixins before components
  • If a component has the same name as a mixin’s methods, the component’s methods are used

Yeah, ok, I haven’t forgotten it, so let’s start executing it sequentially (maybe slightly different).

The hard dish

  • Initialize the data

It is easy to determine whether data is a function or an object, and assign the value to the component’s this.state. Remember that vue data is passed in as a function with the vm of the current instance

function initData(data, vm) { vm.state = { ... (type.isFunction(data) ? data.call(vm, vm) : data), ... vm.state, }; }Copy the code
  • Initialize the computed

To save the trouble of not doing vUE dependency collection, we will intercept directly, mainly get and set operations, he! Tui!

function initComputed(computeOption = {}, descriptors) {
  const keys = getKeys(computeOption);
  const config = {
    configurable: true.enumerable: true}; keys.forEach((key) = > {
    const item = computeOption[key];
    if (descriptors.hasOwnProperty(key)) {
      console.warn('[defineComponent Warning]  The instance already owns the property:' + key);
      return;
    }

    if (type.isFunction(item)) {
      $defineProperty(descriptors, key, { get: item, ... config }); }else if (type.isObject(item)) {
      const { get, set } = computeOption[key];
      $defineProperty(descriptors, key, { get, set, ...config });
    }
  });
  return descriptors;
}
Copy the code
  • Initialize the methods

This is easier to do by putting the Methods object directly into the React class component

function initMethods(from = {}, to) {
  Object.keys(from).forEach((key) = > {
    if (to[key]) {
      return;
    }
    const method = function() {
      return from[key].apply(to, arguments);
    };
    to[key] = method.bind(to);
  });
}
Copy the code
  • Initialize the life cycle

We will attach it to react one by one according to our previous mapping table. Special attention should be paid to watch and the processing of mixins. Therefore, we also follow vUE’s internal principle to queue the life cycle with array, tuI TUI is really difficult

function initLifecycle(from, to) {
  const lifecycle = to.lifecycle;
  Object.keys(from).forEach((key) = > {
    const queue = lifecycle[API[key]] = (lifecycle[API[key]] || []);
    const watchFn = function() {
      initWatch.apply(to, [from[key], to, ... arguments]); }; queue.push(key ==='watch' ? watchFn : from[key]);
    to[API[key]] = function(. res) {
      queue.forEach((item) = > item.apply(to, [...res]));
    };
  });
}
Copy the code
  • Initialize the init

Aggregate the above implementations together for easy invocation (lazy)

function init(option, vm) {
  const{ data = {}, methods = {}, computed, mixins, ... lifecycle } = option; initData(data, vm); initComputed(computed, vm); initMethods(methods, vm); initLifecycle(lifecycle, vm); initMixin(mixins, vm); }Copy the code
  • Next, implement mixins

Personally, I feel that VUE mixin is really practical. In some scenarios, mixin provides us with more aggregation ability. Of course, everything has disadvantages, but I choose to ignore it

function initMixin(mixins = [], vm) {
  if(! mixins.length)return;
  mixins.forEach((mixin) = > {
    init(mixin, vm);
  });
}
Copy the code

After eating the invoicing

React is the app itself, so everything on it is for the service of this device, so the time to admit it


import React from 'react';
export default function defineComponent(option) {
  const { props, render } = option;

  class Super extends React.Component {
    constructor(prop) {
      super(prop);
      this.lifecycle = {};
      init(option, this);
    }

    render = render || function() {
      return null;
    }
  }

  props && (Super.defaultProps = props);

  return Super;
}

Copy the code

reconciliation

Let’s see if the code works (mainly to show how it works)

const mixin = {
  data() {
    return {
      a: 'mixin'.age: 30}},mounted() {
    console.log('mixin-componentDidMount')}},export default defineComponent({
  mixins: [mixin],
  data() {
    return {
      name: Light of Otter.age: 18.profession: 'Didi BUG Engineer'}},computed: {
    info() {
      const {name, age} = this.state;
      return name.concat(The '-', age)
    },
    todo: {
      get() {
        return 'write bugs'
      },
      set() {
        this.setState(Object.assign(this.state, {
          he: 'tui'}}}})),watch: {
    he:'say'.tui(newVal, oldVal) {
      this.say();
    },

    pei: [
      this.say
    ]
  }, 

  methods: {
    say() {
      console.log(this.info)
    }
  },

  mounted() {
    console.log('componentDidMount')},beforeCreate() {
    console.log('constructor')},unmounted() {
    console.log('componentWillUnmount')},render() {
    return (
      <div>Nothing is a series</div>)}})Copy the code

The last

Rookie handwriting, improper processing please refer to (light) teach (spray), welcome to discuss! Thank you! Thank you!