Skip to content
Advertisement

React setState does not update a state array value

I am trying to change the state in a class component by using setState.

More specific I have a table, and I want to edit/update one of its elements. For this case, I am passing the indeces to the handleTableFieldOnChange function for the position of the value in the array.

Since I know that I should not mutate the state, I used an external library to deep copy the tables array/list.

The deep copy and the new value assignment works. The deep copy worked also with the JSON.parse(JSON.stringify(this.state.tables)); alternative.

Problem: For some reason the this.setState(...) does not change the tables value.

I do know the setState is asynchronous, this is why I used the callback and within it, the console.log(...) to check the updated value.

console.log(...) still emits the old value.

private handleTableFieldOnChange(val: boolean | string | number | [number, string], tblRowIndex: number, tblIndex: number, tblColINdex: number) {
        const cloneDeep = require('lodash.clonedeep');
        const newTables = cloneDeep(this.state.tables);
        if (newTables && newTables[tblIndex] && newTables[tblIndex].items ) {
            newTables[tblIndex].items![tblRowIndex][tblColINdex].value = val;
        }
        this.setState( {tables: newTables}, () => {
            console.log(this.state.tables)
        })
    }



state: State = {
  tables: [],
  report: this.props.report,
};

constructor(props: DetailProp, state: State) {
  super(props, state);                                
  this.initFieldsAndTabels();
}

 private initFieldsAndTabels() {
        if (this.state.report && this.state.report.extraction_items) {
            this.state.tables = [];
            this.state.report.extraction_items.forEach((extractionItems) => {
                    this.state.tables.push(extractionItems);
            });
        }
    }

Advertisement

Answer

The code in handleTableFieldOnChange looks fine to me.

However in initFieldsAndTabels you are applying push on state directly instead of calling setState which may probably cause the issues:

this.state.report.extraction_items.forEach((extractionItems) => {
  this.state.tables.push(extractionItems); //#HERE
});

Also as React.Component docs state you should not call setState in constructor (you are calling initFieldsAndTabels in constructor. Instead you could use componentDidMount.

P.S. If you want to add those extraction items in the constructor then you need something like this:

  constructor(props) {
    super(props);
    // method should return a new array/object, but not modify state
    const tables = this.initFieldsAndTabels();
    this.state = {
      tables,
    }
  }
Advertisement