skip to Main Content

THis is my code:

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

const initialState: Conversation | null = null;

export const conversationSlice = createSlice({
  name: "conversation",
  initialState,
  reducers: {
    setConversation: ( // type error
      state: Conversation | null,
      action: PayloadAction<Conversation>
    ) => {
      state = action.payload;
      return state;
    },
  },
});

// Action creators are generated for each case reducer function
export const { setConversation } = conversationSlice.actions;

export default conversationSlice.reducer;

THis is the error I am receiving:

Type '(state: Conversation | null, action: PayloadAction<Conversation>) => Conversation' is not assignable to type 'CaseReducer<null, { payload: any; type: string; }> | CaseReducerWithPrepare<null, PayloadAction<any, string, any, any>>'.
  Type '(state: Conversation | null, action: PayloadAction<Conversation>) => Conversation' is not assignable to type 'CaseReducer<null, { payload: any; type: string; }>'.
    Type 'Conversation' is not assignable to type 'void'.ts(2322)

I know that immer is used under the hood of createSlice. WHen I remove return statement from setCOnversation – error is gone but reducer does not work. If I leave it like that, reducer works (organization sets) but I have an error.

How to fix it ?

I have tried to get rid of return statement, but it brokes application in the other way. ALso read redux toolkit docs

Still getting an error:

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

interface Conversation {
  any_data: string[];
}
const initialState: Conversation | null = null;

export const conversationSlice = createSlice({
  name: "conversation",
  initialState,
  reducers: {
    setConversation: (
      // type error
      state: Draft<Conversation | null>,
      action: PayloadAction<Conversation>
    ) => action.payload,
  },
});

// Action creators are generated for each case reducer function
export const { setConversation } = conversationSlice.actions;

export default conversationSlice.reducer;

Playground

2

Answers


  1. You’re trying to update the state in the reducer. In Redux Toolkit, you should not mutate the state directly, and instead, you should return a new state object.

    export const conversationSlice = createSlice({
      name: "conversation",
      initialState,
      reducers: {
        setConversation: (
          state: Draft<Conversation | null>, // Note the use of Draft<>
          action: PayloadAction<Conversation>
        ) => {
          return action.payload; // Return the new state directly
        },
      },
    });
    
    Login or Signup to reply.
  2. You cannot reassign state in RTK reducers, e.g. state = action.payload is invalid. You can either mutate the draft state or return the new state value (never both).

    I’d argue that the conversation state should not be nullable. With nullable state the UI would need to first check that the state is defined, e.g. not null. I suggest dropping the nullable state and make the conversation state properties optional. The UI will then use a null-check on the conversation state property it accesses.

    Consider the following rewrite:

    import { PayloadAction, createSlice } from "@reduxjs/toolkit";
    
    interface Conversation {
      any_data?: string[];
    }
    const initialState: Conversation = {};
    
    export const conversationSlice = createSlice({
      name: "conversation",
      initialState,
      reducers: {
        setConversation: (state, action: PayloadAction<Conversation>) => {
          return action.payload;
        },
      },
    });
    
    export const { setConversation } = conversationSlice.actions;
    
    export default conversationSlice.reducer;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search