stampit-org / react-stamp

Composables for React.
370 stars 10 forks source link

avoid bind #33

Closed a-ursino closed 8 years ago

a-ursino commented 8 years ago

Hi there's a way to avoid the use of bind for custom handler? http://esnextb.in/?gist=5c9399dfdde739723b7f3f22a32157dd

import React from 'react';
import ReactDOM from 'react-dom';
import reactStamp from 'react-stamp';

const container = {
  state:{
    val: 'click me'
  },
    clickMe(evt) {
        this.setState({val: 'clicked'});
    },
    render() {
      const newHandler = this.clickMe.bind(this);
        return (
            <div className="clearfix">
                <a onClick={newHandler}>{this.state.val}</a>
            </div>
        );
    }
}
const DummyComponent = reactStamp(React).compose(container);
const domHandle = document.getElementById('js-react-entry');
ReactDOM.render(<DummyComponent />, domHandle);

it seems that in this way it doesn't works

import React from 'react';
import ReactDOM from 'react-dom';
import reactStamp from 'react-stamp';

const container = {
  state:{
    val: 'click me'
  },
    clickMe(evt) {
        this.setState({val: 'clicked'});
    },
    render() {
      const handler = this.clickMe;
        return (
            <div className="clearfix">
                <a onClick={handler }>{this.state.val}</a>
            </div>
        );
    }
}
const DummyComponent = reactStamp(React).compose(container);
const domHandle = document.getElementById('js-react-entry');
ReactDOM.render(<DummyComponent />, domHandle);
amelon commented 8 years ago

Actually if you don't use React.createClass there is no automatic binding (https://toddmotto.com/react-create-class-versus-component/).

There's at least two ways to avoid bind.

first one - double colons

const container = {
  state:{
    val: 'click me'
  },
    clickMe(evt) {
        this.setState({val: 'clicked'});
    },
    render() {
        return (
            <div className="clearfix">
                <a onClick={::this.clicMe}>{this.state.val}</a>
            </div>
        );
    }
}

This one is equivalent to <a onClick={this.clicMe.bind(this}>{this.state.val}</a> (http://stackoverflow.com/questions/31220078/javascript-double-colon-es7-proposal)

second one - fat arrow

const container = {
  state:{
    val: 'click me'
  },
    clickMe(evt) {
        this.setState({val: 'clicked'});
    },
    render() {
        return (
            <div className="clearfix">
                <a onClick={(e) => this.clicMe(e)}>{this.state.val}</a>
            </div>
        );
    }
}

This one is equivalent to

...
    render() {
        var _this = this
        return (
            <div className="clearfix">
                <a onClick={function(e) {_this.clicMe(e)}}>{this.state.val}</a>
            </div>
        );
    }
...

(https://strongloop.com/strongblog/an-introduction-to-javascript-es6-arrow-functions/)

For both cases you must use babel but as you use import it should be the case. For double colon you have to use babel stage 0 (http://babeljs.io/docs/plugins/preset-stage-0/).

troutowicz commented 8 years ago

This is by design. We did not want automatic binding as experienced with React.createClass. @amelon has recommended two good alternatives to .bind().

a-ursino commented 8 years ago

Hi yes, i know the double colons feature of ES7 and fat arrow but i want only to avoid this problem jsx-no-bind

thanks anyway

troutowicz commented 8 years ago

@killanaca, ah gotcha. Try using the init method.

const component = {
  init () {
    this.state = {
      val: 'click me'
    };

    this.onClick = this.onClick.bind(this);
  },

  onClick (e) {
    this.setState({ val: 'clicked' });
  },

  render () {
    return (
       <div>
         <a onClick={this.onClick}>{this.state.val}</a>
       </div>
    );
  }
};
a-ursino commented 8 years ago

works. thanks a lot

troutowicz commented 8 years ago

You're welcome!