Michael Brenndoerfer
Michael Brenndoerfer

Reputation: 4066

Updating RTK (redux toolkit) state using other state values

Can I update the state based on other state variables (as shown below in setCurrentQuestion()), or will it cause unexpected issues?

I can think of two workarounds:

  1. "external" helper function that calls a getCurrentQuestionIndex() selector passed into a getQuestionByIndex() selector which returns an IQuestion object that I pass into the setCurrentQuestion() reducer
  2. Keep as is but use a draft safe selector instead of accessing the state object directly
const slice = createSlice({
    name: 'blabla',
    initialState: { questions: undefined, currentQuestion: undefined, noOfQuestions: 0, currentQuestionIndex: 0 } as QuizState,
    reducers: {
        setQuestions: (state, action: PayloadAction<IQuestion[]>) => {
            state.questions = action.payload;
        },
        setCurrentQuestion: (state, action: PayloadAction<number>) => {
            if (!state.questions) return
            state.currentQuestion = state.questions[state.currentQuestionIndex]
        }
    },

Upvotes: 0

Views: 1261

Answers (1)

timotgl
timotgl

Reputation: 2925

state.currentQuestion should simply not exist in your state. You got state.questions as the source of truth, and state.currentQuestionIndex to remember which question is the current question. Anything further is not atomic and minimal anymore. It certainly works to have a state.currentQuestion which duplicates one of the items in state.questions, but then you end up with problems like this one. I'd recommend to add a selector getCurrentQuestion() that does the lookup and that can deal with state.questions being falsy. It also should never not be an array btw, it's easier to deal with state if the types don't change. I'd initialise it as an empty array, and then the selector could be:

const getCurrentQuestion = (state) => state.questions[state.currentQuestionIndex];

To solve what you had in mind, looking at a different part of the state before mutating it in the reducer, you could also use a thunk - they have getState() in the scope and can run conditional logic. So you could simply not dispatch setCurrentQuestion if state.questions is falsy. But a better solution imo is what I described above with the selector.

Upvotes: 1

Related Questions