React series -- the realization idea of react basic syntax

preface

Let's not talk about the syntax principle, but first forcibly simulate the syntax according to the API effect to realize a simple version of React

The following code has nothing to do with the React source code, just a simple simulation idea

render

The first step is to create an element return with the class and bind the click event. The code is as follows. You can normally see that a button appears

class AddButton {
  // Create Dom
  createDOM(domString) {
    const div = document.createElement("div");
    div.innerHTML = domString;
    return div;
  }

  // Output instance
  render() {
    this.dom = this.createDOM(`<button>0</button>`);
    this.dom.addEventListener("click", () => console.log("click"), false);
    return this.dom;
  }
}

// Insert page
document.body.appendChild(new AddButton().render());

state && setState

Implement class state and modify state method

class AddButton {
  // Built in status
  constructor() {
    this.state = { num: 0 };
  }

  // Create Dom
  createDOM(domString) {
    const div = document.createElement("div");
    div.innerHTML = domString;
    return div;
  }

  // Update view with unique modification status
  setState(state) {
    this.state = state;
    this.dom = this.render();
  }

  // Modify data
  handleAdd() {
    const num = this.state.num + 1;
    this.setState({
      num: num
    });
  }

  // Output instance
  render() {
    this.dom = this.createDOM(`<button id="btn">${this.state.num}</button>`);
    this.dom.addEventListener("click", () => this.handleAdd(), false);
    return this.dom;
  }
}

// Insert page
document.body.appendChild(new AddButton().render());

After rendering, you see this The DOM output has been found to have changed, but the view is not rendered because it is a one-time insertion at the end. Let's move on to the render view

Re render

We now built the operation of inserting data into the class and added a new method to insert new elements and remove old elements

class AddButton {
  // Built in status
  constructor() {
    this.state = { num: 0 };
  }

  // Create Dom
  createDOM(domString) {
    const div = document.createElement("div");
    div.innerHTML = domString;
    return div;
  }

  // It's just a way to replace elements
  changeDom() {
    const oDom = this.dom;
    this.dom = this.render();
    document.body.insertBefore(this.dom, oDom);
    document.body.removeChild(oDom);
  }

  // Update view with unique modification status
  setState(state) {
    this.state = state;
    this.changeDom();
  }

  // Modify data
  handleAdd() {
    const num = this.state.num + 1;
    this.setState({
      num: num
    });
  }

  // Output instance
  render() {
    this.dom = this.createDOM(`<button id="btn">${this.state.num}</button>`);
    this.dom.addEventListener("click", () => this.handleAdd(), false);
    return this.dom;
  }
}

// Insert page
document.body.appendChild(new AddButton().render());

Now, although the effect is realized, you still have to manually insert the elements into the view at the beginning

Extract public classes

We first extract some common methods into a separate class, and complete the parameters passed by props attribute

class React {
  // Built in status
  constructor(props = {}) {
    // example
    this.wrapper = null
    // state
    this.state = {}
    // attribute
    this.props = {}
  }

  // Create Dom
  createDOM(domString) {
    const div = document.createElement("div");
    div.innerHTML = domString;
    return div;
  }

  // It's just a way to replace elements
  changeDom() {
    const oDom = this.dom;
    this.dom = this._render();
    this.wrapper.insertBefore(this.dom, oDom);
    this.wrapper.removeChild(oDom);
  }

  // Update view with unique modification status
  setState(state) {
    this.state = state;
    this.changeDom();
  }

  // Output instance
  _render(wrapper) {
    if (wrapper) this.wrapper = wrapper;
    this.dom = this.createDOM(this.render());
    this.dom.addEventListener("click", () => console.log('Add custom event'), false);
    return this.dom;
  }
}

Then, the Component only needs to directly inherit the Component and process its own logic

class AddButton extends React {
  constructor() {
    super();
    this.state = { num: 0 };
  }

  handleAdd() {
    const num = this.state.num + 1;
    this.setState({
      num: num
    });
  }

  render() {
    return `<button id="btn">${this.state.num}</button>`;
  }
}

Several things have been done above:

  1. Extract common logic to React class
  2. Custom component AddButton

Another problem is whether the click event is temporarily coupled into the Component, which will be implemented in the next chapter

Add custom event

Because events are customized by components, our idea is to bind events with generic classes after component instances are defined

class React {
  // Built in status
  constructor(props = {}) {
    // example
    this.wrapper = null
    // state
    this.state = {}
    // attribute
    this.props = {}
    // event
    this.event = {}
  }

  // Create Dom
  createDOM(domString) {
    const div = document.createElement("div");
    div.innerHTML = domString;
    return div;
  }

  // It's just a way to replace elements
  changeDom() {
    const oDom = this.dom;
    this.dom = this._render();
    this.wrapper.insertBefore(this.dom, oDom);
    this.wrapper.removeChild(oDom);
  }

  // Update view with unique modification status
  setState(state) {
    this.state = state;
    this.changeDom();
  }

  // Initialization event
  initEvent() {
    const events = Object.keys(this.event)
    events.forEach(key => {
      this.dom.addEventListener(key, this.event[key].bind(this), false);
    })
  }

  // Output instance
  _render(wrapper) {
    if (wrapper) this.wrapper = wrapper;
    this.dom = this.createDOM(this.render());
    // An instance needs to be created before it can be initialized
    this.dom && this.initEvent()
    return this.dom;
  }
}

At the same time, the component code also needs to be modified accordingly

class AddButton extends React {
  constructor() {
    super();
    this.state = { num: 0 };
    this.event = {
      click: this.handleAdd
    }
  }

  handleAdd() {
    const num = this.state.num + 1;
    this.setState({
      num: num
    });
  }

  render() {
    return `<button id="btn">${this.state.num}</button>`;
  }
}

ReactDom.render

As we all know, React will provide such a method to insert components into a specified element. Let's simulate it directly

const ReactDom = {
  // Inserts a component instance into the specified element
  render(component, wrapper) {
    wrapper.appendChild(component._render(wrapper));
  }
};

Final run code

We have implemented several functions above:

  1. Responsible for creating the React class of elements, including one-way data flow, custom status, events, replacement elements, etc
  2. ReactDom class responsible for mounting
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <div id="root"></div>
  <script>
    class React {
      // Built in status
      constructor(props = {}) {
        // example
        this.wrapper = null
        // state
        this.state = {}
        // attribute
        this.props = {}
        // event
        this.event = {}
      }

      // Create Dom
      createDOM(domString) {
        const div = document.createElement("div");
        div.innerHTML = domString;
        return div;
      }

      // It's just a way to replace elements
      changeDom() {
        const oDom = this.dom;
        this.dom = this._render();
        this.wrapper.insertBefore(this.dom, oDom);
        this.wrapper.removeChild(oDom);
      }

      // Update view with unique modification status
      setState(state) {
        this.state = state;
        this.changeDom();
      }

      // Initialization event
      initEvent() {
        const events = Object.keys(this.event)
        events.forEach(key => {
          this.dom.addEventListener(key, this.event[key].bind(this), false);
        })
      }

      // Output instance
      _render(wrapper) {
        if (wrapper) this.wrapper = wrapper;
        this.dom = this.createDOM(this.render());
        // An instance needs to be created before it can be initialized
        this.dom && this.initEvent()
        return this.dom;
      }
    }

    const ReactDom = {
      // Inserts a component instance into the specified element
      render(component, wrapper) {
        wrapper.appendChild(component._render(wrapper));
      }
    };

    class AddButton extends React {
      constructor() {
        super();
        this.state = { num: 0 };
        this.event = {
          click: this.handleAdd
        }
      }

      handleAdd() {
        const num = this.state.num + 1;
        this.setState({
          num: num
        });
      }

      render() {
        return `<button id="btn">${this.state.num}</button>`;
      }
    }

    ReactDom.render(new AddButton(), document.getElementById("root"));
  </script>
</body>

</html>

So far, leaving aside the practical ideas, we have simply simulated the basic syntax implementation of React

Keywords: Javascript Front-end React

Added by PHPFreaksMaster on Mon, 27 Dec 2021 15:42:39 +0200