All the following code is in a function react component (using FluentUI) with the following state -
const [columns, setColumns] = React.useState<IColumn[]>([]);
I am assigning a method to an object property inside a useEffect hook that's meant to run only once as shown below -
React.useEffect(
() => {
.....
.....
column.onColumnClick = (event, selectedColumn) => setSortingState(selectedColumn);
},
[]);
The setSortingState
function is defined above the useEffect hook as follows -
const setSortingState = (selectedColumn: IColumn) => {
const newColumns: IColumn[] = columns.slice();
..........
..........
setColumns(newColumns);
}
Note that whenever the column is clicked, its state is well-defined. I have verified this using breakpoints in developer tools. However, after clicking the column, when the setSortingState
method is triggered, the state becomes empty (i.e columns = []
). I don't know why this is happening. Please help. Ideally, it should pick up the latest state value. I can't comprehend why it's resetting the state.
EDIT: Will the following work ? I am using 2 states inside the setSortingState
method which I need to update -
const setSortingState = (selectedColumn: IColumn) => {
setColumns(columns => {
const newColumns: IColumn[] = columns.slice();
const newColumnState = columnSortState.slice();
..........
..........
return newColumns;
});
setColumnState(newColumnState);
}
CodePudding user response:
It's an issue of stale state enclosure. The setSortingState
is using a columns
state value from the initial render cycle closed over in callback scope. The state isn't "reset" per se, it's just that the code isn't using the latest state to update from.
Use a functional state update for each state to update from the previous state instead of whatever is closed over in callback scope. In a functional state update the latest state value is passed to the provided updater function.
Example:
const setSortingState = (selectedColumn: IColumn) => {
setColumns(columns => {
const newColumns: IColumn[] = columns.slice();
...
...
return newColumns;
});
setColumnState(columnsState => {
const newColumnState = columnSortState.slice();
...
return newColumnState;
});
}