Public
Authored by Chung Jason

Embed React component in Angular project

Edited
react2angular.service.ts 2.18 KB
namespace app.utils {
  'use strict';

  const { _, React, ReactDOM } = global;

  class NgComponent {
    isFirstRender = true;
    state = {};
    props = {};

    $onChanges(changes) {
      const oldProps = _.mapValues(changes, 'previousValue');
      const newProps = _.mapValues(changes, 'currentValue');
      const nextProps = _.assign({}, this.props, newProps);

      if (this.isFirstRender) {
        _.assign(this, { props: nextProps });
        this.componentWillMount();
        this.render();
        this.isFirstRender = false;
      } else {
        if (!this.didPropsChange(newProps, oldProps)) return;
        this.componentWillReceiveProps(nextProps);
        const shouldUpdate = this.shouldComponentUpdate(nextProps, this.state);
        _.assign(this, { props: nextProps });
        if (!shouldUpdate) return;

        this.componentWillUpdate(this.props, this.state);
        this.render();
        this.componentDidUpdate(this.props, this.state);
      }
    }

    $postLink() {
      this.componentDidMount()
    }

    $onDestroy() {
      this.componentWillUnmount()
    }

    didPropsChange(newProps, oldProps) {
      return _.some(newProps, (v, k) => v !== oldProps[k]);
    }

    componentWillMount() {}
    componentDidMount() {}
    componentWillReceiveProps(props) { }
    shouldComponentUpdate(nextProps, nextState) { return true }
    componentWillUpdate(props, state) {}
    componentDidUpdate(props, state) {}
    componentWillUnmount() {}
    render() {}
  }

  export function react2Angular(ReactComponent, bindingNames = undefined) {
    const propNames = bindingNames
      || (ReactComponent.propTypes && Object.keys(ReactComponent.propTypes))
      || [];

    return {
      bindings: _.fromPairs(propNames.map(_ => [_, '<'])),
      controller: ['$element', class extends NgComponent {
        constructor(private $element) {
          super();
        }
        componentWillUnmount() {
          ReactDOM.unmountComponentAtNode(this.$element[0]);
        }
        render() {
          ReactDOM.render(React.createElement(ReactComponent, this.props), this.$element[0]);
        }
      }]
    };
  }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment