0

Im making a react component that creates multiple buttons but I dont know how to handle the action depending on which button is pressed, this is the component:

var SingleChoiceGroup = React.createClass({
    render(){
        var numberOfButtons = this.props.numberOfButtons;
        var prefix = this.props.prefix;
        var buttons = [];

        for(var i = 0;i<numberOfButtons;i++){
            buttons.push(
                <Button value={i} onClick={() => this.props.selectedItem(i)}>{prefix + " " + (i+1)}</Button>
            );
        }

        return(
            <div>
                {buttons}
            </div>
        )
    }
});

And this is the method were I want to get the parameter:

var AnotherComponent = React.createClass({
    selectedDay(i){
        // Here I want to read the index parameter from the other component.
    },

    render(){
        <SingleChoiceGroup selectedItem={() => this.selectedDay()} numberOfButtons={7} prefix={"Text"}/>
    }    
});

2 Answers 2

1

There are two problems in your code. The first is here:

<SingleChoiceGroup selectedItem={() => this.selectedDay()} numberOfButtons={7} prefix={"Text"}/>

Because your selectedItem arrow function doesn't take any arguments, the i value passed to it by SingleChoiceGroup is lost.

You could solve this by changing it to selectedItem={i => this.selectedDay(i)}, but rather than passing a function that calls this.selectedDay, you can just pass this.selectedDay itself, i.e.:

<SingleChoiceGroup selectedItem={this.selectedDay} numberOfButtons={7} prefix={"Text"}/>

The second problem, as Bartek pointed out in his answer, is that i in our for loop is a reference to the same object in each iteration of the loop, and since its final value is 7, that's the value that the event handler gets for each button. There's a more extensive discussion on that topic in this answer. The TL;DR is to use let instead of var to make the for loop initialize a new block-scoped variable each time.

Here are both of those changes in a working snippet:

const Button = props => <button type="button" {...props}/>;

var SingleChoiceGroup = React.createClass({
    render(){
        var numberOfButtons = this.props.numberOfButtons;
        var prefix = this.props.prefix;
        var buttons = [];

        for (let i = 0; i < numberOfButtons; i++){
            buttons.push(
                <Button key={i} value={i} onClick={() => this.props.selectedItem(i)}>{`${prefix} ${i+1}`}</Button>
            );
        }
        
        return <div>{buttons}</div>;
    }
});

var AnotherComponent = React.createClass({
    selectedDay(i){
      console.log('clicked %d', i);
    },

    render(){
        return <SingleChoiceGroup selectedItem={this.selectedDay} numberOfButtons={7} prefix="Text"/>
    }    
});

ReactDOM.render(<AnotherComponent/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Click on us: <div id="container"></div>

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

3 Comments

Sorry Im pretty new to react, what exactly does "bind something" means, I've tried selectedItem={this.selectedDay} but I always get the same value (7) in selectedDay method
I've fixed the issue you mentioned and updated my answer with a working snippet. "Bind" is not a term from React, it's a term from JavaScript. The reason you (may) need to use it is explained here: facebook.github.io/react/docs/handling-events.html (Scroll down to the paragraph beginning "You have to be careful...")
Thanks, now I understand the difference between var and let
1

In your SingleChoiceGroup component use let insetad of var in for loop - otherwise click handlers will use last value of i which is 7 in your case (why? please see this SO answer for detailed explanation of closures in for loops):

 for(let i = 0;i<numberOfButtons;i++){
        buttons.push(
            <Button value={i} onClick={() => this.props.selectedItem(i)}>{prefix + " " + (i+1)}</Button>
        );
    }

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.