JSFiddle - React, Tailwind, and code Playground

by Ilya

JavaScript

class Block {
  static EVENTS = {
    INIT: "init",
    FLOW_CDM: "flow:component-did-mount",
    FLOW_CDU: "flow:component-did-update",
    FLOW_RENDER: "flow:render"
  };

_element = null;
_meta = null;

/** JSDoc
   * @param {string} tagName
   * @param {Object} props
   *
   * @returns {void}
   */
constructor(tagName = "div", props = {}) {
  const eventBus = new EventBus();
  this._meta = {
    tagName,
    props
  };

  this.props = this._makePropsProxy(props);

  this.eventBus = () => eventBus;

  this._registerEvents(eventBus);
  eventBus.emit(Block.EVENTS.INIT);
}

_registerEvents(eventBus) {
  eventBus.on(Block.EVENTS.INIT, this.init.bind(this));
  eventBus.on(Block.EVENTS.FLOW_CDM, this._componentDidMount.bind(this));
  eventBus.on(Block.EVENTS.FLOW_CDU, this._componentDidUpdate.bind(this));
  eventBus.on(Block.EVENTS.FLOW_RENDER, this._render.bind(this));
}

_createResources() {
  const { tagName } = this._meta;
  this._element = this._createDocumentElement(tagName);
}

init() {
  this._createResources();
  this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
}

_componentDidMount() {
  this.componentDidMount();
  
  Object.values(this.children).forEach(child => {
    child.dispatchComponentDidMount();
  });
}

// Может переопределять пользователь, необязательно трогать
componentDidMount(oldProps) {
  
}

dispatchComponentDidMoun() {
  this.eventBus().emit(Block.EVENTS.FLOW_CDM);
}

_componentDidUpdate(oldProps, newProps) {
  const response = this.componentDidUpdate(oldProps, newProps);
  if (response) {
    this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
  }
}

// Может переопределять пользователь, необязательно трогать
componentDidUpdate(oldProps, newProps) {
  return oldProps !== newProps;
}

setProps = nextProps => {
  if (!nextProps) {
    return;
  }

  Object.assign(this.props, nextProps);
};

get element() {
  return this._element;
}

_render() {
  const block = this.render();

    this._removeEvents();

    this._element!.innerHTML = block;

   ...