2

I am very new to react and am trying to create a checkbox and also display the selected checkbox names list in a textbox. I am using selected[] to store the values for the selected box and checked[] to store whether that box is checked or not.If it is checked I update the value of selected accordingly.

The code as of now works fine but I want to avoid use of forceupdate() and use setState(). When I use I am unable to update the selected[] value using it. Can somebody tell me of how to update the particular array index value using setstate so thatit gets render itself and I do not have to use forceupdate() ?

thank you.

var history = React.createClass({

getInitialState : function(){
    return {
        checked : [],
        selected: []
    };
},

componentWillMount : function(){

}, 

handleChangechk: function (e){

    const target = e.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    if(value===true)
    {
        this.state.checked[name]= true;
        this.state.selected[name] = name;
        this.forceUpdate();

    }
    else
    {
        this.state.checked[name]= false;
        this.state.selected[name] = '';
        this.forceUpdate();
    }
},

render : function() {

    var historyList = [];
    var selectedList = [];

    for (var i = 0; i < 10; i++) {
        historyList.push(<span  key={i}><input type="checkbox"  name = {i} checked={!!this.state.checked[i]} onChange ={(e)=> this.handleChangechk(e)}/><span ></span><label >checkbox {i}</label></span>);
        if(this.state.selected[i])
        {
            selectedList.push(this.state.selected[i]);
        }
    };


return(   /* display selected checkbox (selectedList ); */}});

3 Answers 3

2

Never mutate the state variable directly by this.state.a.push() or this.state.a = '', always use setState to update the value.

From Doc:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

forceUpdate() is not required if you update the state values properly, it will automatically do the re-rendering, Check this:

class App extends React.Component{

  constructor(){
     super();
     this.state = {value: [], selected: []}
  }
   
  change(event) {
    let target, value, selected;

    target = event.target;
    value = this.state.value.slice();
    selected = this.state.selected.slice();

    value[target.name] = target.checked;

    if(target.checked){
        selected.push(target.name);
    }else{
        let index = selected.indexOf(target.name);
        selected.splice(index, 1);
    }

    this.setState({
       value, selected
    });
  }

  render(){
  
    return(   
      <div>
          {[1,2,3,4,5].map((el,i)=>{
             return <div key={i}>
                <input checked={this.state.value[i]} type='checkbox' onChange={this.change.bind(this)} name={i}/>
                Item- {el}
             </div>
          })}

          Selected Values: {JSON.stringify(this.state.selected)}

       </div>
      
    )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>

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

Comments

1

You could get a copy of the checked and selected arrays, change the relevant index and then update the state:

handleChangechk: function (e) {
    const target = e.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    let checked = this.state.checked.slice(),    
        selected = this.state.selected.slice();

    if(value === true) {
        checked[name]= true;
        selected[name] = name;
    } else {
        checked[name]= false;
        selected[name] = '';
    }

    this.setState({ items, selected });
}

Comments

0

You should almost never assign values to your state directly and/or use forceUpdate:

    this.state.checked[name]= true;
    this.state.selected[name] = name;
    this.forceUpdate();

Avoiding the use of forceUpdate is as simple as using setState to assign the values. setState will automatically trigger a re-render.

var newChecked = this.state.checked.slice();
newChecked[name] = true;
var newSelected = this.state.selected.slice();
newSelected [name] = name;
this.setState({
    checked: newChecked,
    selected: newSelected,
});

3 Comments

there is a issue in setState, it will throw error, it should be checked: newChecked, instead of this.state.checked: newState :)
Thanks Cesar and Mayank works fine, for the same code I get warning "Warning: Failed form propType: You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly. Check the render method..." any idea how can I get rid of it?
Thanks for the correction @MayankShukla :) Jayant, you should check his great answer.

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.