Ricerca nel sito web

javascript - Redux + Typescript -> Errore: Un case reducer su un valore non modificabile non deve restituire undefined redux


Sto cercando di importare TypeScript nella mia applicazione Redux. Uso la funzione createSlice di Redux Toolkit in questo modo:

const slice = createSlice({
  name: sliceName,
  initialState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      state = action.payload.mode;
    },
  },
});

Quando invio un'azione updateMode, ricevo il seguente errore:

Error: A case reducer on a non-draftable value must not return undefined

Ma il mio action.payload è ben definito e Redux Toolkit è aggiornato. Ha a che fare con il mio codice, ma non riesco a capirlo...

Ho provato a restituire lo stato in updateMode e funziona, ma ottengo un errore TypeScript:

Type '(state: SliceState, action: { payload: ModePayload; type: string; }) => SliceState' is not assignable to type 'CaseReducer<"SHOW_LIST", { payload: any; type: string; }> | CaseReducerWithPrepare<"SHOW_LIST", PayloadAction<any, string, any, any>>'.
  Type '(state: SliceState, action: { payload: ModePayload; type: string; }) => SliceState' is not assignable to type 'CaseReducer<"SHOW_LIST", { payload: any; type: string; }>'.
    Type 'SliceState' is not assignable to type 'void | "SHOW_LIST"'.
      Type '"SHOW_SKILL"' is not assignable to type 'void | "SHOW_LIST"'

Qualcuno può spiegarmi cosa sto facendo di sbagliato?

Di seguito il mio codice completo:

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

type SliceState = "SHOW_LIST" | "SHOW_SKILL";

let initialState: SliceState = "SHOW_LIST";

const sliceName = "mode";

interface ModePayload {
  mode: SliceState;
}

//--- Slice reducer ---

const modeSlice = createSlice({
  name: sliceName,
  initialState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      return (state = action.payload.mode);
    },
  },
});
export const { updateMode } = modeSlice.actions;
export default modeSlice.reducer;

Risposta n. 1

Sono un manutentore di Redux e il creatore di Redux Toolkit.

Il problema reale è con questa riga:

state = action.payload.mode;

Questo in realtà non realizza nulla di utile. Immer funziona tracciando le mutazioni a un valore esistente, come state.someField=123. La riga che hai scritto cambia solo la variabile locale state per puntare a qualcos'altro invece.

Immer richiede che tu restituisca un valore di stato completamente nuovo, oppure muti lo stato esistente. Quella riga di codice non fa né l'una né l'altra cosa. Invece, il reducer finisce solo per restituire undefined, da cui l'errore.

Se vuoi sostituire completamente lo stato esistente, dovresti semplicemente fare return action.payload.mode.

Inoltre, come nota a margine: se initialState è correttamente tipizzato, non è necessario fornire un tipo per state per ogni reducer, poiché verrà dedotto.

Risposta n. 2

Seguendo il documento, potrebbe essere necessario eseguire il cast del tuo tipo come segue:

const modeSlice = createSlice({
  name: sliceName,
  initialState: initialState as SliceState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      return (state = action.payload.mode);
    },
  },
});