Получение актуального состояния одного слайса при работе с другим - Redux Toolkit
Я относительно новичок в Redux Toolkit, и решение этой проблемы нигде найти н могу.
Разрабатываю приложение для прохождения тестов, имею два слайса - testSlice (хранит состояние текущего теста) и resultsSlice (результаты всех тестов). Объединить слайсы нельзя, я использую redux-persist для работы с localStorage и сохраняю только общие результаты.
Суть проблемы: Нет доступа к актуальному состоянию сразу после того, как метод отработал. testSlice реализует метод addToCurrentResult() - добавляет ответ на вопрос в массив результатов текущего теста. Затем, если вопрос последний, отрабатывает метод addToResults() из слайса resultsSlice, который принимает состояние testSlice и создаёт на его основе объект результата теста. Далее добавляет его в массив результатов всех тестов (либо меняет, если тест пройден заново).
В коде происходит вызов двух диспатчей этих методов подряд и в общем массиве не хватает ответа на последний вопрос. (4 вопроса - ожидается массив из 4-х элементов, но приходит из 3-х)
Вроде обычное действие, и кажется можно решить с помощью extraReducers, но объяснений мало, все используют примитивные типы данных для примера.
Компонент:
import React, { useState } from "react";
import Answer from "../Answer/Answer";
import styles from "./AnswerList.module.css";
import { useDispatch, useSelector } from "react-redux";
import { nextQuestion, addToCurrentResult } from "../../store/slices/testSlice";
import { addToResults } from "../../store/slices/resultsSlice";
import { useNavigate } from "react-router-dom";
import NextQuestionBtn from "../UI/NextQuestionBtn/NextQuestionBtn";
const AnswerList = (props) => {
const {
testId,
answers,
questionAmount,
currentQuestionIndex,
correctAnswerIndex,
} = props;
const dispatch = useDispatch();
const navigate = useNavigate();
const [selectedAnswerIndex, setSelectedAnswerIndex] = useState(null);
const currentTest = useSelector((state) => state.test.currentTest);
const currentResult = useSelector((state) => state.test.currentResult);
const currentResultCounter = useSelector((state) => state.test.currentResultCounter);
const testsState = {
currentTest,
currentResult,
currentResultCounter
}
const onNextQuestionClick = (event) => {
// вызывается на последнем вопросе
if (currentQuestionIndex >= questionAmount - 1) {
dispatch(
addToCurrentResult({ selectedAnswerIndex, correctAnswerIndex }),
);
dispatch(addToResults(testsState)); // получает неактуальное состояние
navigate(`/test/${testId}/result`); // currentTestResult будет очищен
return;
}
dispatch(addToCurrentResult({ selectedAnswerIndex, correctAnswerIndex }));
dispatch(nextQuestion({ selectedAnswerIndex }));
setSelectedAnswerIndex(null);
};
return (
<form className={styles.controls}>
<div className={styles.answersList}>
{answers.map((answer, i) => (
<Answer
key={answer + i + currentQuestionIndex}
answer={answer}
id={"answer" + i + currentQuestionIndex}
value={i}
setSelectedAnswerIndex={setSelectedAnswerIndex}
/>
))}
</div>
<NextQuestionBtn
onNextQuestionClick={onNextQuestionClick}
selectedAnswerIndex={selectedAnswerIndex}
/>
</form>
);
};
export default AnswerList;
addToResults в resultSlice
addToResults(state, action) {
const testsState = action.payload;
console.log(testsState)
const resultIndex = state.results.findIndex(
(result) => result.testId === testsState.currentTest.id
);
const result = {
testId: testsState.currentTest.id,
resultCounter: testsState.currentResultCounter,
results: testsState.currentResult,
};
if (resultIndex === -1) {
state.results.push(result);
} else {
state.results[resultIndex] = result;
}
},
},