Select Page

Bagi yang menggunakan React dengan ES6 maka akan menulis lebih banyak code karena method tidak otomatis terbind dengan this.

Selain itu manual binding method di dalam render function dianggap antipattern: https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f

Inilah yang biasa kita lakukan ketika menggunakan ES6 class di React.

class App extends React.Component{
    constructor(props){
        super(props);

        //Manual binding methods
        this.func1 = this.func1.bind(this);

        this.state = {foo: 'FOO'};
    }

    func1(){
        alert(`${arguments.callee.name} - ${this.state.foo}`);
    }

    func2(){
        alert(`${arguments.callee.name} - ${this.state.foo}`);
    }

    render(){
        return (
            <div>
              Apps <hr/>
              <button onClick={this.func1}>button1</button>
              {/*Manual binding inside render is antipattern*/}               
              <button onClick={this.func2.bind(this)}>button2</button>
            </div>            
        )
    }   
}

ReactDOM.render(<App/>, window.reactRoot);

Saya telah mengalami ini, manual binding dimana-mana.
Untuk itulah saya coba create base class yang bertujuan melakukan binding otomatis method-method pada class.

Define BaseComponent sebagai BaseClass yang akan kita gunakan untuk autobinding:

//Declare BaseComponent for autobinding
class BaseComponent extends React.Component {
    constructor(props) {
        super(props);

        this.bindMethodsToThis();
    }

    getMethodNames() {
        const excludes = [
            'constructor',
            'componentWillMount',
            'render',
            'componentDidMount',
            'componentWillReceiveProps',
            'shouldComponentUpdate',
            'componentWillUpdate',
            'componentDidUpdate',
            'componentWillUnmount',
            'bindMethodsToThis'
        ];
        const props = Object.getOwnPropertyNames(this.constructor.prototype);
        const names = [];
        for (let p of props) {
            const p2 = this[p];
            if (typeof p2 === 'function' && excludes.indexOf(p) === -1) {
                names.push(p);
            }
        }
        return names;
    }

    bindMethodsToThis() {
        const methods = this.getMethodNames();

        methods.forEach((item) => {
            this[item] = this[item].bind(this);
        });
    }
}

Dan cara menggunakannya dengan subclass dari BaseComponent yang kita define diatas:

//Subclass from BaseComponent
class App extends BaseComponent{
    constructor(props){
        super(props);

        //No need for manual binding
        //this.func1 = this.func1.bind(this);
        //this.func2 = this.func2.bind(this);

        this.state = {foo: 'FOO'};
    }

    func1(){
        alert(`${arguments.callee.name} - ${this.state.foo}`);
    }

    func2(){
        alert(`${arguments.callee.name} - ${this.state.foo}`);
    }

    render(){
        return (
            <div>
              Apps <hr/>
              <button onClick={this.func1}>button1</button>
              <button onClick={this.func2}>button2</button>
            </div>            
        )
    }   
}

Demo:
http://jsbin.com/cocila/edit?js

Semoga berguna.

Happy Coding 🙂

%d bloggers like this: