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,
}
}