Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstraction in React.js

I want to use some abstraction in the creation of my React components. For example:

class AbstractButton extends React.Component {
  render() {
    return (
      <button
        onClick={this.props.onClick}
        className={this.definitions.className}>
        {this.props.text}
      </button>
    }
}
class PrimaryButton extends AbstractButton {
  constructor(options) {
    super(options);
    this.definitions = {
        className: 'btn btn-primary'
    };
  }
}
class SuccessButton extends AbstractButton {
  constructor(options) {
    super(options);
    this.definitions = {
        className: 'btn btn-success'
    };
  }
}

I don't want to pass these definitions via props because I know that these definitions--in this case the class--will never change.

Is it an anti-pattern in React? Or is it OK?

My question refers to this altjs issue: this kind of abstraction isn't compatible with @connectToStores.

like image 454
mqklin Avatar asked Nov 24 '15 13:11

mqklin


1 Answers

Generally speaking, there's no reason not to use composition here instead of deep inheritance:

class Button extends React.Component {
  render() {
    return (<button
             onClick={this.props.onClick}
             className={this.props.className}
           >
             {this.props.text}
           </button>);
  }
  static propTypes = {
      className: React.PropTypes.string.isRequired,
      onClick: React.PropTypes.func
  }
}

class PrimaryButton extends React.Component {
  render() {
    return <Button {...this.props} className="btn btn-primary" />;
  }
}

This is just as functional as what you propose, but is a lot simpler and easier to reason about. It makes it very clear what information your Button actually needs to do its work.

Once you make this leap, you can eliminate the classes altogether and use stateless components:

const Button = (props) => (<button
             onClick={props.onClick}
             className={props.className}
           >
             {props.text}
           </button>);
Button.propTypes = {
      className: React.PropTypes.string.isRequired,
      onClick: React.PropTypes.func
};

const PrimaryButton = (props) =>
    <Button {...props} className="btn btn-primary" />;

const SuccessButton = (props) =>
    <Button {...props} className="btn btn-success" />;

This will allow React to apply more optimizations since your components do not need any special lifecycle event support or state management. It is also even easier to reason about since now you are just working with pure functions.

As an aside, if you are trying to make some React components that wrap Bootstrap, then perhaps you should take a look at React-Bootstrap.

like image 193
Brandon Avatar answered Oct 12 '22 23:10

Brandon