The working code at the end of chapter Component class

index.js

function createVComponent(tag, props) {
  return {
    tag: tag,
    props: props,
    dom: null,
  }
}

function createVElement(tag, config, children = null) {
  const { className, style } = config;

  return {
    tag: tag,
    style: style,
    props: {
      children: children,
    },
    className: className,
    dom: null,
  }
}

function createElement(tag, config, children) {
  // If the tag is a function. We have a component!
  // we will see later why. 
  if (typeof tag === 'function') {
    //of course we could do some checks here if the props are 
    //valid or not.
    const vNode = createVComponent(tag, config);
    return vNode;
  }

  //Add children on our props object, just as in React. Where
  //we can acces it using this.props.children;

  const vNode = createVElement(tag, config, children);
  return vNode;
}


function mount(input, parentDOMNode) {
  if (typeof input === 'string' || typeof input === 'number') {
    //we have a vText
    return mountVText(input, parentDOMNode);
  } 
  else if (typeof input.tag === 'function') {
    //we have a component
    return mountVComponent(input, parentDOMNode);
  }
  // for brevity make an else if statement. An
  // else would suffice. 
  else if (typeof input.tag === 'string') {

    //we have a vElement
    return mountVElement(input, parentDOMNode)
  }
}

function mountVComponent(vComponent, parentDOMNode) {
  const { tag, props } = vComponent;

  // build a component instance. This uses the 
  // defined Component class. For brevity 
  // call it Component. Not needed ofcourse, new tag(props)
  // would do the same. 
  const Component = tag;
  const instance = new Component(props);

  // The instance or Component has a render() function 
  // that returns the user-defined vNode.
  const nextElement = instance.render();

  // the nextElement can be a vElement or a
  // vComponent. mountVComponent doenst't care. Let the mount()
  // handle that!
  const dom = mount(nextElement, parentDOMNode);
  //append the DOM we've created.
  parentDOMNode.appendChild(dom);

  return dom;
}

function mountVText(vText, parentDOMNode) {
  // Oeeh we received a vText with it's associated parentDOMNode.
  // we can set it's textContent to the vText value. 
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
  parentDOMNode.textContent = vText;
}

function mountVElement(vElement, parentDOMNode) {
  const { className, tag, props, style } = vElement;

  const domNode = document.createElement(tag);
  vElement.dom = domNode;
  if (props.children) {
     // Oeh, we have children. Pass it back to our mount
     // function and let it determine what type it is.
     props.children.forEach(child => mount(child, domNode));
  }

  if (className !== undefined) {
    domNode.className = className;
  }

  if (style !== undefined) {
    Object.keys(style).forEach(sKey => domNode.style[sKey] = style[sKey]);
  }

  parentDOMNode.appendChild(domNode);

  return domNode;
}

class Component {
  constructor(props) {
    this.props = props || {};
  }
  setState(partialNewState) {
    // Awesome things to come
  }
  //will be overridden
  render() {}
}

//get native DOM, For now let's use the body;
const root = document.body;
//create vElement
class App extends Component {
  render() {
    return createElement('div', { style: { height: '100px', background: 'red'} }, [
      createElement('h1', {}, [ this.props.message ])
    ]);
  }
}

mount(createElement(App, { message: 'Hello there!' }), root);

results matching ""

    No results matching ""