0

I'm new to React and the concepts are still new to me. I'm working on this example and I would like to know if it would be possible to re-write it in another way and avoid using .bind altogether. The goal here is just to minimize the code written required as much as possible!

Full example can be found here:

https://codepen.io/akamali/pen/awvqeM

The component simply render a menu list and when you click on an item it highlight the selected text.

ES5

<ul className='languages'>
      {languages.map(function (lang) {
        return (
          <li
            style={lang === this.state.selectedLanguage ? {color: '#d0021b'} : null}
            onClick={this.updateLanguage.bind(null, lang)}
            key={lang}>
              {lang}
          </li>
        )
      }, this)}
    </ul>

**ES6 => **

<ul className='languages'>
      {languages.map(lang => {
        return (
          <li
            style={lang === this.state.selectedLanguage ? {color: '#d0021b'} : null}
            onClick={this.updateLanguage.bind(null, lang)}
            key={lang}>
              {lang}
          </li>
        )
      },)}
    </ul>
user2398069
  • 385
  • 1
  • 5
  • 13
  • 1
    `() => this.updateLanguage(lang)` – zerkms Jun 08 '17 at 09:12
  • @zerkms that is not preferred as it is less performant than .bind – John Ruddell Jun 08 '17 at 09:13
  • @JohnRuddell "as it is less performant than .bind" --- it is implementation specific. The standard does not tell how one should perform. And it would be transpiled anyway. – zerkms Jun 08 '17 at 09:16
  • if updateLanguage's body has code like `this.x` then binding to null will make it throw NullPointerException, you probably want to bind to `this` – niceman Jun 08 '17 at 09:18
  • check this another way of binding (using arrow function): https://codepen.io/anon/pen/VWvxby?editors=0010 – Mayank Shukla Jun 08 '17 at 09:20
  • "less code" is not, of itself, a good reason to adopt a particular style. – RobG Jun 08 '17 at 09:20
  • @zerkms no as in defining inline functions generally has a performance impact on your code (when in the render) https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md – John Ruddell Jun 08 '17 at 09:24
  • @JohnRuddell your last message which I am agree with does not correlate with what you said initially: "as it is less performant than .bind" – zerkms Jun 08 '17 at 09:26
  • @zerkms .bind is more performant than an inline arrow function. Let me find the tests that prove it :). Someone ran time tests to verify. – John Ruddell Jun 08 '17 at 09:28
  • @JohnRuddell performance of the new ES201x features improve from release to release. – zerkms Jun 08 '17 at 09:28
  • 1
    @zerkms that is true. It could be different :) I need to look at any differences of when .bind is used or when an inline arrow is used. Before they were compiled differently.. but that could have changed since now. Good point! – John Ruddell Jun 08 '17 at 09:37

2 Answers2

2

What you want to do is make each item a component, this way there is no inline binding in your render

{languages.map(lang => <ListItem lang={lang} updateLanguage={this.updateLanguage} selected={lang === this.state.selectedLanguage } />)}

and then your list item handles the click with a single bound instance.

class ListItem extends Component {
    handleClick = () => {
        this.props.updateLanguage(this.props.lang);
    }
    render() {
        return (
            <li 
                style={this.props.selected ? {color: '#d0021b'} : null}
                onClick={this.handleClick}
            >
                {this.props.lang}
            </li>
        )
    }
}
John Ruddell
  • 25,283
  • 6
  • 57
  • 86
  • You also need to bind `this.handleClick` in the constructor. – zerkms Jun 08 '17 at 09:25
  • 1
    @zerkms no because handleClick is an arrow function. assuming your compiler accepts the arrow on function declaration. Thats how I write all of my functions I want bound in a react class – John Ruddell Jun 08 '17 at 09:26
  • 1
    Oh, I did not know that, thanks. It's not standardised yet though. – zerkms Jun 08 '17 at 09:27
  • @zerkms yea, if you are using babel to compile then [this answer](https://stackoverflow.com/a/31362350/2733506) would help someone get setup. I like typescript and with typescript using the ts-loader in webpack the fat arrow functions are standardized! – John Ruddell Jun 08 '17 at 09:42
  • It's class member variables https://tc39.github.io/proposal-class-public-fields. Fat arrows are there from ES2015. – zerkms Jun 08 '17 at 09:45
  • @John Ruddell I'm not sure if you could put a working example in codepen or pastbin, as I'm still confused with your answer. Thanks – user2398069 Jun 08 '17 at 18:51
  • @user2398069 what part of my answer is confusing? i can help explain it better if you can let me know :) – John Ruddell Jun 08 '17 at 18:52
  • @user2398069 here is your codepen updated with my answer. https://codepen.io/anon/pen/qjOeyP – John Ruddell Jun 08 '17 at 19:02
-1

First you bind to null, if updateLanguage has code like this :

updateLanguage(lang){
    this.x;
}

It will throw a null pointer exception, you probably wanted to bind to this.

Now why would anyone bind ? to explain this look at example definition of updateLanguage :

updateLanguage(lang){
    this.setState({language: lang});
}

In this function we want this to be the React component as we're using setState here.

But when you register events with this function then whoever triggers the event will be this inside updateLanguage's body, so this above will be e.g. li which doesn't have setState.

By binding you make sure this will be the component, anyway you can get rid of binding by doing this :

<li
    onClick={() => this.updateLanguage(lang)}            
</li>

Because when registering it as an arrow function we're actually registering a closure which closes over this which is the component here, I leave it to you whether you like this style or not.

Another way is to use propery syntax initializer e.g. :

updateLanguage : (lang) => {
}

And then

  <li
      onClick={this.updateLanguage(lang)}            
  </li>

These ways are mentioned in React Docs by the way, see here : https://facebook.github.io/react/docs/handling-events.html

niceman
  • 2,653
  • 29
  • 57