4

I have a ul li list inside the render method and there is an onClick event on li which call this.handleClick function and state gets changed

var InspirationFilter = React.createClass({
    getInitialState: function() {
        return {currentFilterText:"Top All Time", currentFilter:"top_all_time", showUl:false};
    },
    handleClick: function(filter, filterText){
        this.setState({currentFilterText:filterText, currentFilter:filter, showUl:!this.state.showUl});
    },
    render: function() {
        return (
            <ul>
                <li onClick={this.handleClick('top_all_time', 'Top All Time')}>Top All Time</li>
                  <li onClick={this.handleClick('top_this_week', 'Top This Week')}>Top Week</li>
                <li onClick={this.handleClick('top_this_month', 'Top This Month')}>Top Month</li>
            </ul>
        );
    }
});

But this code gives me the error

Warning: setState(...): Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state

I tried to use bind with the click event like this,

return (
    <ul>
        <li onClick={this.handleClick.bind(this,'top_all_time', 'Top All Time')}>Top All Time</li>
        <li onClick={this.handleClick.bind(this,'top_this_week', 'Top This Week')}>Top  Week</li>
        <li onClick={this.handleClick.bind(this.'top_this_month', 'Top This Month')}>Top  Month</li>
    </ul>
);

The above error is gone now but ran into another error which is as follows,

Warning: bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call. See InspirationFilter

In the react documentation Communicate Between Components they are also using the bind method.

Any suggestions to fix it?

9
  • 1
    You're third li has a . after this instead of , - is that in your source code or just here? Commented Nov 5, 2015 at 21:23
  • What version of React are you using? I'm not able to recreate the issue in the second example. FWIW it's not an error, just a warning Commented Nov 5, 2015 at 21:29
  • @Mat yes that was my mistake regarding the (dot). Now the click event is working but i am still having the warning. Is there is any better way to do it without warning? Commented Nov 5, 2015 at 21:30
  • I am using React v0.14.1 Commented Nov 5, 2015 at 21:32
  • I'll try to replicate, in the meantime try binding null instead of this when you are binding your parameters Commented Nov 5, 2015 at 21:33

3 Answers 3

6

The problem is that onClick value has to be a function, so just create a helper method that creates such a function for you:

createClickHandler: function(filter, filterText){
    return function() {
        this.setState({...});
    }.bind(this);
},

render: function() {
    return (
        <ul>
            <li onClick={this.createClickHandler('top_all_time', 'Top All Time')}>Top All Time</li>
            <li onClick={this.createClickHandler('top_this_week', 'Top This Week')}>Top Week</li>
            <li onClick={this.createClickHandler('top_this_month', 'Top This Month')}>Top Month</li>
        </ul>
    );
}

React is really just a bit over-helpful here with its warning. Your reason for using bind() is no to bind this, but rather to bind the arguments.

Why it works? This solution avoids the re-binding warning because it's not re-binding an already bound this.handleClick, but instead creating a new function (that's not yet bound to anything) and binding that.

Sign up to request clarification or add additional context in comments.

12 Comments

That doesn't solve his problem and is incorrect JSX syntax, it's actually the same as the first example he gave which invokes the function instead of passing a reference to it
The issue is that you pass functions in React as a reference to that function, you're invoking it instead. Meaning the correct syntax is onClick={this.myFunction} not onClick={this.myFunction()}
The contents of {...} can be any valid JavaScript expression. For onClick the expression must evaluate to a function, which I think my code does.
But your code invokes the function, meaning if you change state in your function you have an infinite loop, which is why in the same example he was getting an error. Read the question again..
No. During render() my code only invokes createClickHandler() which returns a function that's assigned to onClick. Only when onClick finally fires will it call the created function, that in turn calls setState().
|
3

To summarize, in your first example, when you use this format:

onClick={this.functionName(arg1, arg2)

you are calling the functions rather than providing a reference to the functions. Hence they are being called directly every time it is being rendered rather than onClick as intended.

When you use the format:

onClick={this.functionName.bind(this, arg1, arg2)}

you are providing a reference to the function and binding context and arguments, rather than calling it. This is the correct method; ignore the warnings (even though there are way too many and it's really annoying)

Comments

1

Yes, you do need to pass a function to onClick.

You have a typo on the third <li>

return (
    <ul>
        <li onClick={this.handleClick.bind(this,'top_all_time', 'Top All Time')}>Top All Time</li>
        <li onClick={this.handleClick.bind(this,'top_this_week', 'Top This Week')}>Top  Week</li>
        <li onClick={this.handleClick.bind(this, 'top_this_month', 'Top This Month')}>Top  Month</li>
    </ul>
);

Check this Fiddle https://jsfiddle.net/69z2wepo/20047/ It works on React 0.14

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.