5

I'm following a tutorial to update states in ReactJS. I came across this line in the tutorial this.updateLanguage = this.updateLanguage.bind(this) and I don't understand what is going on. I understand the basics of this and bind, but I've never seen it done like this before. Can someone please explain? The full code:

var React = require('react');

class Popular extends React.Component {
    // constructor to set default state
    constructor (props) {
        super(props);
        this.state = {
            selectLanguage: 'All'
        };
        // I don't understand this line
        this.updateLanguage = this.updateLanguage.bind(this);
    }
    // updates state
    updateLanguage(lang) {
        this.setState(() => {
            return {
                selectLanguage: lang
            }
        });
    }
    render() {
        var languages = ['All', 'JavaScript', 'Ruby', 'Java', 'CSS', 'Python'];
        return (
            <ul className='languages'>
                {languages.map((lang) => {
                    return (
                        // adds listener to current state
                        <li style={lang === this.state.selectLanguage ? {color: '#d0021b'}: null}
                            onClick={this.updateLanguage.bind(null, lang)} 
                            key={lang}>
                            {lang}
                        </li>
                    )
                })}
            </ul>
        )
    }
} 

module.exports = Popular;
David
  • 303
  • 3
  • 8
  • 21
  • 1
    JavaScript classes do not bind methods to the instance of the class by default. so if you didn't have that line `this.setState` will fail – azium Dec 24 '17 at 03:03
  • You didn't answer my question. I'm having trouble understanding what is happening with `this.updateLanguage = this.updateLanguage.bind(this)` – David Dec 24 '17 at 03:07
  • Well I tried to answer your question. That line binds the instance of the class (`this`) to the method, so that inside the method `updateLanguage`, `this` will refer to the instance of the class – azium Dec 24 '17 at 03:12
  • 2
    It's due to the context where it is called in an event handler. The context there makes `this` context point at the element and the first argument is `event` Another way without using bind is `onClick={()=> this.updateLanguage(lang)}` – charlietfl Dec 24 '17 at 03:14
  • @azium what you have stated is not true – charlietfl Dec 24 '17 at 03:18
  • @charlietfl What am I misunderstanding? I feel like what both of us said is true (though your comment easier to understand) – azium Dec 24 '17 at 03:20
  • A class does bind `this` in the prototype methods so long as context is maintained – charlietfl Dec 24 '17 at 03:21
  • ah yes indeed, thanks – azium Dec 24 '17 at 03:23
  • https://gist.github.com/fongandrew/f28245920a41788e084d77877e65f22f will be helpful – Anupama Karunarathna Jul 08 '20 at 15:05

2 Answers2

10

DOM callbacks such as click events will set the this context to the DOM element itself, in this case the li. Try removing the part you don't understand and see what happens - you'll see something like this.setState is not defined, because that function isn't defined in the context of the li element (it's basically looking for li.setState).

What bind is doing on that line is ensuring that whenever that function gets called, it will get called with the this context we want, in this case the Popular component - e.g. Popular.setState.

These days it's getting more and more common to see folks just using fat arrow syntax as a shorthand to preserve the this context - e.g. in this case onClick={ () => this.updateLanguage(lang) }.

(note for those concerned about performance: the fat arrow approach is cleaner but somewhat controversial since it's repeatedly declaring the function on every single render. That said, some folks claim there is minimal or no significant performance impact.)

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
David Calhoun
  • 8,315
  • 4
  • 30
  • 23
  • If you don't bind the `this`, then the `this` context will be `undefined` rather than the element that was clicked. While that behavior occurs for standard HTML `onclick=` events, it doesn't occur with the JSX prop `onClick={}` – Nick Parsons Oct 14 '21 at 07:52
1

If you not getting the bind(this) in constructor then its not but one of the way to avoid binding in render

Now why we need bind(this) in render let say we generally use onChange={this.handleChange.bind(this)}

These approaches assume that you’re declaring React components using ES6 classes. If you use an ES6 class, React no longer autobinds.

So, this is the One way to resolve this is to call bind in render.

Jatin parmar
  • 424
  • 4
  • 13