ReactJs - Using Mixins with ES6

Continued on video Egghead.io - "React Components in ES 6 classes", below works:

 'use strict';
 import React from 'react';
 import Button from './components/form/button';
 import Label from './components/form/label';

      


 // after refactoring
 //import ReactMixin from './super-classes/react-mixin';

      

// ToDo: Reactor below

 let reactMixin =  InnerComponent => class extends React.Component {
     constructor() {
         super()
         this.state = {count: 0}

    //binding custom methods
    this.increment = this.increment.bind(this);
}


increment() {
    this.setState({count: this.state.count + 1});
}

render() {
    return (
        <InnerComponent update={this.increment} {...this.state} {...this.props} />
    )
   }
 }

      


 let ButtonMixed = reactMixin(Button); // using local variable
 let LabelMixed = reactMixin(Label); // using local variable

   class App extends React.Component {
      render(){
     return(<section>
         // WOULD LIKE TO DO
         // <ReactMixin component={?Button?} />
         // <ReactMixin component={?Label?} />

         <LabelMixed txt="I am a mixed label calling a form component" />
           <ButtonMixed txt="I am a mixed button, me too! " />
       </section>);
      }
    }


  App.propTypes = {txt: React.PropTypes.any};
  module.exports = App;

      

Problem:

I am trying to refactor ReactMixins into a separate component, import it and then just use it in my render, like this:

          <ReactMixins component={?} />

      

Any ideas on the best way to refactor this for reusability?

Thank...

+3


source to share


2 answers


Update: After working with LOT more with ES6 React components, I'm much more into the compositional approach, but I'll leave my answer here for posterity.

Mixins come out, prefer composition or inheritance instead.

If I understand your situation correctly, it is easiest to create a "base" component that you inherit. Something like:

export default class BaseButton extends React.Component {

  constructor(){
    super();
    //Set default state... if you want to
  }

  componentWillMount() {
     console.log("I will run anytime someone extends baseButton");
  }

  //etc

}

      

where all your Button logic is located, you can extend it like this



Then:

export default class MyButton extends BaseButton {
   //I will already have the things that BaseButton has
}

      

now you have whatever you want through super()

or this.whatever()

.

If you prefer a compositional approach, I recommend this as a good one:

https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

+6


source


My solution is for ES6 mixins if you are using decorators.



/**
 * This is the ES6 mixin helper
 *
 * mixins {Array} Array of mixin objects
 *  mixin:
 *    optional name: {String} mixin name
 *    optional lifecycleMethods: {Object} lifecycle methods
 *    optional instances: {Object} instance methods
 *    optional statics: {Object} statics methods
 * component {Object} Abstract component
 *
 * return component {Object} mixed component
 */
export default function ES6Mixin (mixins) {
  return function (component) {
    const warn = function (type, method, mixinName) {
      console.warn(
        new component(),
        `already has \`${method}\` ${type} method, it overwritten by \`${mixinName}\` mixin`
      );
    };

    mixins.forEach((mixin) => {
      const { name, statics, instances, lifecycleMethods } = mixin;
      const _componentWillMount = component.prototype.componentWillMount;

      if (statics instanceof Object) {
        Object.keys(statics).forEach((method) => {
          if (statics[method] instanceof Object) {
            component[method] = Object.assign({}, statics[method], component[method]);
          } else {
            if (this[method]) {
              warn('statics', method, name || 'anonym');
            }
            this[method] = statics[method];
          }
        });
      }

      if (instances instanceof Object) {
        component.prototype.componentWillMount = function () {
          Object.keys(instances).forEach((method) => {
            if (this[method]) {
              warn('instance', method, name || 'anonym');
            }

            this[method] = instances[method].bind(this);
          });

          if (_componentWillMount) {
            _componentWillMount.apply(this, arguments);
          }
        };
      }

      if (lifecycleMethods instanceof Object) {
        Object.keys(lifecycleMethods).forEach((method) => {
          let _lifecycleMethod = component.prototype[method];

          component.prototype[method] = function () {
            lifecycleMethods[method].apply(this, arguments);

            if (_lifecycleMethod) {
              _lifecycleMethod.apply(this, arguments);
            }
          };
        });
      }
    });

    return component;
  };
}

      

+1


source







All Articles