Eugen
Eugen

Reputation: 2990

How to make a base class for ReactJS classes

How would I make a base class for my ReactJS components where I'd encapsulate some common behavior for all of the descendants.

Right now I have at least 3 classes that have a common method functionality

  handleClick: function (e) {
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
    this.props.onClick(this.props.value);
  },

which is copy/pasted. :(((

Coming from the C#, where I'd split everything into smallest possible pieces, this really bugs me.

Ideally I'd like to have such a method in base class

  handleClick: function (e) {
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
    onClick(); // this method would be virtual in base class and overridden in children classes
  },

Is it possible to achieve this in ReactJS? Or what would be another best approach for such functionality in ReactJS or JavaScript world?

Thx

Upvotes: 1

Views: 1906

Answers (4)

Neil Twist
Neil Twist

Reputation: 1159

Have you considered using React Mixins.

This would allow you to define the function centrally and just mixin where you need it.

var HandleClickMixin = {
  handleClick: function (e) {
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
    this.props.onClick(this.props.value);
  }
};

Which can then be used:

var SomeReactComponent = React.createClass({
  mixins: [HandleClickMixin],
  render: function() {
    return (
      <button onClick={this.handleClick}>
        Click Me.
      </button>
    );
  }
});

You still need to provide the onClick and value props, but otherwise it's a one line addition.

Upvotes: 2

pierrepinard_2
pierrepinard_2

Reputation: 1426

In ReactJS world, it's generally preferred to use composition patterns over classical inheritance.

In your case, you could use the higher-order component pattern (very well explained in this post by Dan Abramov) like this:

// higher-order component creator:
function getClickHandlerComponent(OriginalComponent) {

    const ClickHandlerComponent = React.createClass({
        handleClick: function(e) {
            e.stopPropagation();
            e.nativeEvent.stopImmediatePropagation();
            this.props.onClick(this.props.value);
        },
        render: function() {
            return (
                <OriginalComponent
                    {...this.props}
                    handleClick={this.handleClick}
                />
            );
        },
    });

    return ClickHandlerComponent;  // higher-order component (HOC)
}

// Used like this:
const SomeButton = getClickHandlerComponent(React.createClass({
    propTypes: {
        // original props,
        handleClick: React.PropTypes.func.isRequired,  // added by the HOC
    },
    render: function() {
        return (
            <input
                type="button"
                value="Click me"
                onClick={this.props.handleClick}
            />
        );
    },
}));

The functionality which is provided by the higher-order component (here, the "handleClick" handler) can be added to any component that needs it: the component simply receives it in its props.

Upvotes: 1

ZekeDroid
ZekeDroid

Reputation: 7209

Multiple ways

ES6 Classes: If you're using ES6 classes you can create a base class that extends Component from react and then extend your components from this base class

Context: If you take a look at react-router you can get more implementation details but in short, context is shared by all children and grandchildren so you could make your base component and then pass down methods to the children.

Upvotes: 0

omarjmh
omarjmh

Reputation: 13888

I would think of it more like a utility function that handles clicks, thats said, there are a number of ways to do this. Lets say we have a utility function(s) in a file called utils.js:

// utils.js
export function someUtilityFunction (a) {
  return axios.all(players.map(function (username) {
    return getUserInfo(username)
  }))
  .then(function (info) {
    return info.map(function (user) {
      return user.data
    })
  })
  .catch(function (err) {console.warn('Error in func: ', err)})
};


Then in another file, lets say Main.js:

// Main.js
import { someUtilityFunction } from from '../utils/';

// someUtilityFunction is now available in this file

Note the export and import keywords.

Above I am using ES6 syntax, which needs to be transpiled down to ES5 for the browser (I use babel.js);

Take a look at these docs to see variations of this in both ES5 and ES6:

MDN docs on export

Upvotes: 0

Related Questions