'Redux-toolkit useSelector doesn't update

So I use redux-toolkit for a form. The form is made up of 3 tabs. Each tab has some inputs. I store the errors and values in redux. After I save the form, saveFrom is called, but the redux state doesn't update only after it rerendered or I click save again.

So basically It only shows the right data on every second save. Why is that? Doesn't the useSelector need to update when it's state changes?

ProgressSlice:

import { createSlice, current } from "@reduxjs/toolkit";

export const progressSlice = createSlice({
    name: "progress",
    initialState: {
        errors: {},
        results: {}
    },
    reducers: {
        addErrorById: (state, { payload: action }) => {

            const { text, id } = action
            //console.log(current(state).errors[id])
            state.errors = {
                ...state.errors,
                [id]: [
                    text
                ]
            }
        },
        deleteErrorById: (state, { payload: id }) => {
            delete state.errors[id]
        },
        createResult: (state, { payload }) => {
            const { id, type, required } = payload
            state.results = {
                ...state.results,
                [id]: {
                    "id": id,
                    "value": (type === 'boolean' || required === false) ? 0 : null
                }
            }
        },
        addResult: (state, { payload }) => {
            const { formValue, id, type } = payload

            let value = null;

            if (type === 'list') {
                const { good, bad } = formValue;
                good ? value = good : value = bad;
            } else {
                value = formValue * 1
            }

            state.results = {
                ...state.results,
                [id]: {
                    "id": id,
                    "value": value
                }
            }
        }
    }
})

export const { addErrorById, deleteErrorById, addResult, createResult } = progressSlice.actions;
export const progressReducer = progressSlice.reducer;

TabContent.js:

export default function TabContent({ task }) {

    const res = useSelector((state) => state.progress.results);
    const err = useSelector((state) => state.progress.errors);
    const progressDispatch = useDispatch()
    const totalScore = useSelector((state) => state.score.count);
    const Scoredispatch = useDispatch()
    const formDispatch = useDispatch()
    const formData = useSelector((state) => state.form.tasks);
   

    const [formValues, setFormValues] = useState(
        task.reduce((prev, curr) => {
            const value = formData[curr.id] ? formData[curr.id].formValue : null;
            return {
                ...prev,
                [curr.id]: {
                    ...curr,
                    formValue: value
                }
            }
        }, {})
    );

    const canSubmit = () => {
        // But here it doesn't seem to be updated
        console.log("SUBMIT",res)
        console.log("ERRS",err)
        const can = Object.entries(res).every((result) => result[1].value !== null)
                    && Object.keys(err).length === 0
        if(can) console.log("CAN SAVE")
        else console.log("CANNOT SAVE")
    }

    const saveFrom = (e) => {
        e.preventDefault()
        console.log("SAVE")
        Object.entries(formValues).forEach(([key, e]) => {
            //console.log(e)
            let isError = false
            if (e.type === 'number') {
                if (e.formValue !== null && e.formValue !== '')
                    const val = e.formValue;
                    if (Number.isFinite(val * 1)) {
                        if (!(val <= e.maxValue && val >= 0)) {
                            progressDispatch(addErrorById({ 'text': Errors.OUTOFRANGE + e.maxValue + Errors.TEXTHELP, 'id': e.id }))
                            isError = true;
                        }
                    } else {
                        progressDispatch(addErrorById({ 'text': Errors.NOTNUM, 'id': e.id })) 
                        isError = true;
                    }
                } else if (e.required) {
                    progressDispatch(addErrorById({ 'text': Errors.REQUIRED, 'id': e.id }))
                    isError = true;
                }
            } else if (e.type === 'list') {
                if (e.formValue === null && e.required) {
                    //console.log("EZ")
                    progressDispatch(addErrorById({ 'text': Errors.REQUIRED, 'id': e.id }))
                    isError = true;
                }
            }
            
            if(!isError){
                // Here I update redux-state
                progressDispatch(deleteErrorById(e.id))
                progressDispatch(addResult(e))
                formDispatch(setValueById(e))
            }
        })
        canSubmit()
    }
    
    return (
        <form>
            <Table>
                <TableHead>
                    <TableRow>
                        <TableCell>#</TableCell>
                        <TableCell>Szempont megnevezése</TableCell>
                        <TableCell>{task[0] ? getColLabel() : "Nincs szempont"}</TableCell>
                        <TableCell>Szempont leírása</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {task.map((row) => (
                        <TableRow
                            key={row.name}
                        >
                            <TableCell>{row.id}</TableCell>
                            <TableCell>{row.name}</TableCell>
                            <TableCell>{getGradingType(row, formValues, setFormValues)}</TableCell>
                            <TableCell>{row.description ? row.description : 'Nincs leírás'}</TableCell>
                        </TableRow>
                    ))}
                </TableBody>
            </Table>
            {task[0] && <FormActions save={saveFrom}></FormActions>}
            <div>{totalScore}</div>
        </form>
    )
}



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source