In react class, you must have binded functions like this

class Person extends React.Component{
    constructor(props){
        super(props)
        this.state = {
           name: "Joe"
        }
        this.handleOnClick = this.handleOnClick.bind(this)
        console.log(JSON.stringify(this))
    }

    handleOnClick(){
        alert(this.state.name)
    }

    render(){
        return(
            <div>
                <button onClick={this.handleOnClick}> Click Me </button>
            </div>
        )
    }
}

ReactDOM.render(<Person />, document.querySelector("#app"))

You are binding the function handleOnClick this.handleOnClick = this.handleOnClick.bind(this).

If you do not bind the function, then the state will not be defined inside the render function.

If you console.log this inside the Person class, you can see following properties.

{
context: undefined,
handleOnClick: fn(),
props: {},
refs: {},
state: { name: "Joe" },
updater: { 
       enqueueForceUpdate: ƒ (publicInstance, callback, callerName),
       enqueueReplaceState: ƒ (publicInstance, completeState, callback, callerName),
       enqueueSetState: ƒ (publicInstance, partialState, callback, callerName),
       isMounted: ƒ (publicInstance)
   }
}

So when you do this.handleOnClick = this.handleOnClick.bind(this), you are passing the scope of Person class to the handleOnClick function and this.state is defined.

Understanding this

Suppose you have a object like this

this.name = "Joe"
var module = {
   name: "Sam",
   getName: function(){
      return this.name;
   }
}

When you run

module.getName()
> Sam // this.name will be Sam, as this refers to function context.

But when you run

var result = module.getName;
result() // this.name will be "Joe" as this refers to window object
> Joe

If you run module.getName(), then this refers to scope of module, and not the global scope. So this.name resolves to "Sam".

But when you assign module.getName to result, and call result(), then this refers to global scope. So this.name will be resolved to "Joe"

If you had not defined this.name = "Joe", then result() would be undefined

var module = {
   name: "Sam",
   getName: function(){
      return this.name;
   }
}
var result = module.getName;
result() 
undefined // as this.name refers to global scope here and is not defined, the result be undefined.

If you want to pass the module scope to name, then you can use bind function.

var module = {
   name: "Sam",
   getName: function(){
      return this.name;
   }
}
var result = module.getName.bind(module);
result() 
> Sam // as we have binded module scope to name

Similarly, if you want to bind some other scope (object), you can do so

var module = {
   name: "Sam",
   getName: function(){
      return this.name;
   }
}
var newScope = {
 name: "Jenny"
}
var name = module.getName.bind(newScope);
name() 
> Jenny // as we have binded module scope to name

How does bind function work

bind function passes the scope to the function you binded to. Here is the polyfill for bind function in javascript

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}

Here the point to note is

fToBind.apply((this instanceof fNOP
                 ? this
                 : oThis),
aArgs.concat(Array.prototype.slice.call(arguments)));

So the function which is to be bind is called with apply of arguments. For example

function module(){
    console.log(this.name);
}
module()
> undefined
module.apply({name:'abc'})()
> abc

When you use module.apply with the scope object ({name:'abc'}), the this.name will be 'abc'

Other ways to bind function in react jsx

  1. Bind the function in constructor as mentioned at start of blog.
  2. Use arrow functions. Arrow functions are available from es6. Arrow functions pass the scope automatically.For example
this.name = "Joe"
var module = {
name: "Sam",
    getName: () => {
        return this.name;
    }
}
> module.getName() 
> Joe
> var result = module.getName
> result()
> Joe

3.  So by using arrow functions, the scope is passed on to the function. So this.name will be "Joe".Similarly, when you use arrow function to define handleOnClick, the this will be passed on automatically.

class Person extends React.Component{
    constructor(props){
        super(props)
        this.state = {
           name: "Joe"
        }
        this.handleOnClick = this.handleOnClick.bind(this)
        console.log(JSON.stringify(this))
    }
    
    handleOnClick = () => {
        alert(this.state.name) /* here this.state will be defined as we are using arrow function */
    }

    render(){
        return(
            <div>
                <button onClick={this.handleOnClick}> Click Me </button>
            </div>
        )
}

ReactDOM.render(<Person />, document.querySelector("#app"))

4.   You can use arrow function inside onclick in render method. But this method is not recommended as it will create new bindings every time the render method is called. When you pass props to child component, or get props from parent component, and the props are changed, the render method is called. So new bindings will be created then.

class Person extends React.Component{
    constructor(props){
        super(props)
        this.state = {
           name: "Joe"
        }
        this.handleOnClick = this.handleOnClick.bind(this)
    }
    
    handleOnClick(){
        alert(this.state.name)
    }

    render(){
        return(
            <div>
                <button onclick={()=>handleOnClick}>Click Me</button>
            </div>
        )
}