imperium2335
imperium2335

Reputation: 24112

ReactJS onClick not firing

I have:

...

setActive(section) {
        this.setState({
            currentSection: section
        });
        console.log('Current view is'+this.state.currentSection);
    }

    render() {
        return <div>
            <div className="section">
                <HeaderButton active text="test1" count={23} backgoundColor={'#c04c36'} onClick={() => this.setActive.bind('test1')}/>
            </div>
            <div className="section">
                <HeaderButton text="test2" count={45} backgoundColor={'#ffe698'} onClick={() => this.setActive.bind('test2')}/>
            </div>
            <div className="section">
                <HeaderButton text="test3" count={4} backgoundColor={'#198a75'} onClick={() => this.setActive.bind('test3')}/>
            </div>
        </div>
    }

But when I click on those component nothing at all happens. What am I doing wrong?

Upvotes: 2

Views: 61

Answers (3)

Sam
Sam

Reputation: 74

The problem is that you are both using the arrow function, and binding as well. You are also not binding to an execution context.

This is a confusing concept.

When you call an onClick without an arrow function, you need to bind it.

Thus, a call like this...

onClick = {this.setActive.bind(this)}

Needs to be called or else this.setActive will lose its binding. It is bound to the execution context that you would like it to run in, in this case that being this

An ES6 arrow function is lexically bound and does not need to be bound to an execution context.

thus, you can have...

onclick ={() => this.setActive()}

Which will automatically run in the context where it is written, thus not needing the binding.

Also, you are binding to a string instead of an execution context (usually a component).

Take out the bind and your function should run.

Upvotes: 1

Dacre Denny
Dacre Denny

Reputation: 30360

Avoid calling .bind() in the onclick handler itself. Instead, you can call setActive() directly via the this variable seeing that the context of the arrow function is that of your component:

render() {
    return <div>
        <div className="section">
            <HeaderButton active text="test1" count={23} 
                          backgoundColor={'#c04c36'} 
                          onClick={() => this.setActive('test1')}/>
        </div>
        <div className="section">
            <HeaderButton text="test2" count={45} 
                          backgoundColor={'#ffe698'} 
                          onClick={() => this.setActive('test2')}/>
        </div>
        <div className="section">
            <HeaderButton text="test3" count={4} 
                          backgoundColor={'#198a75'} 
                          onClick={() => this.setActive('test3')}/>
        </div>
    </div>
}

Alternatively, to optimize your render() method, you could create pre-bound function instances to avoid use of arrow functions in your render method:

constructor(props) {
 super(props);

 /* Bind setActive to this component/class instance */
 this.setActiveTest1 = this.setActive.bind(this, 'test1')
 this.setActiveTest2 = this.setActive.bind(this, 'test2')
 this.setActiveTest3 = this.setActive.bind(this, 'test3')
}

setActive(section) {
    this.setState({
        currentSection: section
    });
    console.log('Current view is'+this.state.currentSection);
}

render() {
    return <div>
        <div className="section">
            <HeaderButton active text="test1" count={23} 
                          backgoundColor={'#c04c36'} 
                          onClick={this.setActiveTest1 }/>
        </div>
        <div className="section">
            <HeaderButton text="test2" count={45} 
                          backgoundColor={'#ffe698'} 
                          onClick={this.setActiveTest2}/>
        </div>
        <div className="section">
            <HeaderButton text="test3" count={4} 
                          backgoundColor={'#198a75'} 
                          onClick={this.setActiveTest3}/>
        </div>
    </div>
}

Upvotes: 0

Paul Losev
Paul Losev

Reputation: 1089

You should bind your events in constructor but not in attribute itself.

Upvotes: 0

Related Questions