0
votes

I'm building component with multiple checkboxes - each for a category.

When I have only one checkbox in boolean var, it works perfectly(similar like in Thinking in React), but when I put states in an array, I'm getting the uncontrolled form warning:

react.js:20541 Warning: CheckComponent is changing a controlled input of >type checkbox to be uncontrolled. Input elements should not switch from >controlled to uncontrolled (or vice versa). Decide between using a >controlled or uncontrolled input element for the lifetime of the >component.

Component:

handleChange: function(e) {
    this.props.onUserInput(
        this.refs[e.target.name].checked
    );
},
render: function(){
    var self = this;
    return(
        <div>
            <ul>
                {
                categories.map(function(d, i){
                    return (
                            <li key = {d}>
                                <input type="checkbox" checked={self.props.checkedBox[i]} name={d} ref={d} onChange={self.handleChange}/>
                                <span> {d} </span>
                            </li>
                        );
                })
                }
            </ul>
        </div>
    );
}

Parent component:

getInitialState: function(){
  return{
      checkedBox: [true,true,true,true,true,true,true,true,true,true]
  };  
},
handleUserInput: function(checkedBox) {
    this.setState({
        checkedBox: checkedBox
    });
},
render: function(){
    return(
        <div>
            <CheckComponent checkedBox={this.state.checkedBox} onUserInput={this.handleUserInput} categories={this.props.categories}/>
            <DisplayComponent checkedBox={this.state.checkedBox} data={this.props.data}/>
        </div>
    );
}

Is something wrong with this array?

2
Have you looked at using a library to take care of it for you? react-checkbox-group already takes care of maintaining the state of your checkboxes and can be used both as a controlled and uncontrolled component.ziad-saab

2 Answers

0
votes

You do not have a 'value' attribute in your input element. React Documentation says

An without a value property is an uncontrolled component

render: function() {
    return <input type="text" />;
}

This will render an input that starts off with an empty value. Any user input will be immediately reflected by the rendered element. If you wanted to listen to updates to the value, you could use the onChange event just like you can with controlled components.

An uncontrolled component maintains its own internal state.

0
votes

You are replacing array in your state with single value. Just pass checkbox index to onChange function.

handleChange: function(i) {
    this.props.onUserInput(i);
},

...

<input type="checkbox" checked={self.props.checkedBox[i]} name={d} ref={d} onChange={function() {self.handleChange(i);}}/>

Then in your user input just change value at specified index.

handleUserInput: function(i) {
    this.setState({
        checkedBox: this.state.checkedBox.map(function(val, idx) {
                        if (idx === i) return !val; 
                        return val;
                    );
    });
},