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

Viewed 180

In my Next.js app,I have implemented a very simple redux logic to change my spinner state, I added the <Spinner /> component in _app.js so whenever my spinner state is true it will show up regardless on which page I'm on, however when in my index.js (home page) I dispatch a function that turns the spinner on then off I get the following error:

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

And I cannot understand why, here is my code:

store.js

import { configureStore } from "@reduxjs/toolkit";

import spinnerReducer from "./slices/spinnerSlice";

const store = configureStore({
    reducer: {
        spinner: spinnerReducer,
    },
});

export default store;

spinnerSlice.js

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

const spinnerSlice = createSlice({
    name: "spinner",
    initialState: true,
    reducers: {
        turnSpinnerOn: (state) => {
            state = true;
        },
        turnSpinnerOff: (state) => {
            state = false;
        },
        setSpinnerState: (state, action) => {
            if (typeof action.payload === "boolean") {
                state = action.payload;
            }
        },
    },
});

export const { turnSpinnerOn, turnSpinnerOff, setSpinnerState } = spinnerSlice.actions;

export default spinnerSlice.reducer;

index.js (HomePage)

import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { turnSpinnerOn, turnSpinnerOff } from "../redux/slices/spinnerSlice";

import HomeHero from "../components/PageSections/HomePage/HomeHero/HomeHero";

const Home = () => {
    const dispatch = useDispatch();
    const spinnerState = useSelector((state) => state.spinner);

    useEffect(() => {
        dispatch(turnSpinnerOn());
        console.log("spinner state = ", spinnerState);
        let i = 0;
        for (i; i < 10000; ++i) console.log("i = ", i);
        console.log(" c log ");
        dispatch(turnSpinnerOff());
    }, []);

    return (
        <>
            <HomeHero />
        </>
    );
};

export default Home;

_app.js

import Header from "../components/Layout/Header/Header";
import Footer from "../components/Layout/Footer/Footer";

import { Provider } from "react-redux";
import store from "../redux/store";
import Spinner from "../components/UI/Spinner/Spinner";

import "bootstrap/dist/css/bootstrap.min.css";
import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
    return (
        <Provider store={store}>
            <Header />
            <Component {...pageProps} />
            <Footer />

            <Spinner />
        </Provider>
    );
}

export default MyApp;

I tried changing my initialState to a javascript object that contains a property of "initialSpinnerState" set to false and changed everything accordingly which removed the error however the spinner never shows.

Note that I didn't include the code of the <Spinner /> component because I know that the component isn't the problem because when I set the initialState in my reducer to true and remove the useEffect hook from the home page, the spinner does show.

Edit: I changed the slice to return true, false & action.payload respectively (instead of making the state equal to these values) and the error did disappear howerver the state doesn't change.

1 Answers

The structure of your reducers is wrong.

 reducers: {
        turnSpinnerOn: (state) => {
            state = true;
        },
        turnSpinnerOff: (state) => {
            state = false;
        },
        setSpinnerState: (state, action) => {
            if (typeof action.payload === "boolean") {
                state = action.payload;
            }
        },
    },

Each key in the reducers object should be a function that receives (state) or (state, action) as arguments, and should RETURN (not set) the new state.

So in this example your reducer object should read:

 reducers: {
        turnSpinnerOn: (state) => {
            return true;
        },
        turnSpinnerOff: (state) => {
            return false;
        },
        setSpinnerState: (state, action) => {
            if (typeof action.payload === "boolean") {
                return action.payload;
            }
            return state;
        },
    },
Related