12

I'm just learning React and I am writing components using ES7 syntax. My idea is to create a base component which will contain some methods that I want all derived components to have. For example, I want to implement valueLink without the mixin, for two-way binding in all my components. Here is my idea:

class MyComponent extends React.Component {

    bindTwoWay(name) {
        return {
            value: this.state[name],
            requestChange: (value) => {
                this.setState({[name]: value})
            }
        }
    };
}

 

class TextBox extends MyComponent {
    state = {
        val: ''
    };

    render() {
        return (<div>
            <input valueLink={this.bindTwoWay('val')}/>
            <div>You typed: {this.state.val}</div>
        </div>)
    }
}

And it works just fine. However, I wasn't able to find much information about this method. It's not about valueLink, that was just an example. The idea is to have some methods in a base component and later extend that component so that derived components have all those methods, like the usual OOP way. So I would just like to know if this is perfectly fine or there are some flaws that I am not aware of. Thanks.

tuks
  • 800
  • 3
  • 11
  • 27
  • 1
    Most people would say "no". Prefer composition over inheritance. However, that doesn't always work, yours might be one of these cases. *"or there are some flaws"* The biggest difference between inheritance and mixins is that a class can use many mixins, but it can only have one parent. That makes inheritance much less flexible. – Felix Kling Feb 09 '16 at 20:49
  • 1
    +1 to @FelixKling, composition over inheritance where possible. I'd rather see a component that did something like `const bindTwoWay = require('../mixins/bindTwoWay')` explicitly than chasing down something in a nested hierarchy. – Gabriel Isenberg Feb 09 '16 at 20:50
  • @FelixKling I see your point, but still, even if class can have one parent, and if I really only need one parent, this would still be perfectly fine thing to do, right? Since we can't use mixins with ES6 syntax... – tuks Feb 09 '16 at 20:57
  • From my experience with large projects, you should always add base classes and also try to wrap everything when possible. No matter the framework. Even if it's empty. This will save you a ton of work later. This will also allow you to upgrade your technologies much easily. Most people will say no, but that's why most people are just most people. – Cesar Aug 20 '20 at 11:29
  • Prefer thing != Always do thing. I think the others are not considering "...that I want all derived components to have." and how fundamental something like 2-way binding is (other frameworks bake that feature in). This is literally where you'd want to use inheritance. – GHOST-34 Dec 24 '21 at 01:06

2 Answers2

7

This is totally fine, it is just basic inheritance. The caveat of using inheritance to replace mixins is that there is no multiple inheritance, so you cannot give your TextBox features of multiple base classes as you would when you give it multiple mixins. To get around this you can use component composition. In your case composition would not work directly as you defined in the example but there is an workaround to this.

First you need to define a composing component

export default (ComposedComponent) => {
  class MyComponent extends React.Component {
    constructor(props, state) {
      super(props, state);
      this.state = {
        val: ''
      };
    }
    bindTwoWay(name) {
      return {
        value: this.state[name],
        requestChange: (value) => {
            this.setState({[name]: value})
        }
      };
    }

    render() {
      return (
        <ComposedComponent 
          {...this.props}
          {...this.state} 
          bindTwoWay={this.bindTwoWay.bind(this)}
        />
      }
    }
  }

  return MyComponent
}

And then you define your component where you need some common features

import compose from 'path-to-composer';

class TextBox extends React.Component {
  render() {
    return (
      <div>
        <input valueLink={this.props.bindTwoWay('val')}/>
        <div>You typed: {this.props.val}</div>
      </div>
    )
  }
}

export default compose(TextBox)

I have not tested this but it should work.

Jarno Lonardi
  • 303
  • 1
  • 7
  • 1
    Ths won't work. It should be `{this.props.val}` instead of `{this.state.val}`. And you should do the initialization in the higher order component. – fl0cke Feb 09 '16 at 21:28
4

I would not recommend to create your own base component and drive from them rather use composition as suggested by react documentation also. enter image description here https://reactjs.org/docs/react-component.html#overview

Vikas Gupta
  • 1,293
  • 1
  • 15
  • 21