2

I thought it was the case that the this keyword always refers to the component in React, but in my toggleStyle method in the below this is returning the window object instead of the React component object . Can somebody help me to understand why that is?

renderDeviceToggle() {

    var arrowAnimation = {
        rotateX: this.state.expanded ? 180 : 0,
        transformOriginY: [ '42%', '42%' ]
    };

    let toggleState = function () {
        // 'this' is the window
        console.log("in toggleState: this: ", this)
        this.setState({expanded: !this.state.expanded});
    };

    return (
        <div className="device-toggle" onClick={toggleState}>
            <div>{console.log("in return: this is the component: ", this)}</div>
            <div className="device-icon icon huge"></div>
            <VelocityComponent duration={300} animation={arrowAnimation}>
                <div className="icon color-blue flex">
                    <i className="icon-caret-down"></i>Hi
                </div>
            </VelocityComponent>
        </div>
    );
},

render() {
    return (
        <div>
            <div className="panel panel-default">
                <div className="panel-heading">
                    <div className="pull-right text-right">
                        <p><a href="/addOrder" className="pull-right">New order </a></p>
                        <p><a href="#"> View all</a></p>
                    </div>
                    <h4>Top orders</h4>
                </div>
                <div className="panel-body">
                    { this.data.orders ?
                        this.renderOrderTable() :
                        <p>Loading</p> }
                </div>
                <div>
                    {this.renderDeviceToggle()}
                </div>
            </div>
        </div>
    );
}
tomRedox
  • 18,963
  • 13
  • 90
  • 126

2 Answers2

4

You can use arrow functions to get lexically bound this:

let toggleState = () => {
    // 'this' should be the component
    console.log("in toggleState: this: ", this)
    this.setState({expanded: !this.state.expanded});
};

Or explicitly bind the context:

let toggleState = function () {
    // 'this' should be the component
    console.log("in toggleState: this: ", this)
    this.setState({expanded: !this.state.expanded});
}.bind(this);

As to the how and why this works in JS here's a great explanation https://stackoverflow.com/a/3127440/4879

Community
  • 1
  • 1
pawel
  • 30,843
  • 6
  • 50
  • 50
4

The reason this is happening is because React only binds the top level functions in your class to 'this'. So in this case both render and renderDeviceToggle are bound as you would expect. However, inside renderDeviceToggle you have created a new function,toggleState, that React doesn't know about. Therefore, this code works under the normal javascript rules when a function is created.

As mentioned in another answer, to solve you would need to use the arrow context or explicitly bind the new function to 'this'.

LodeRunner28
  • 1,426
  • 1
  • 12
  • 15