Search code examples
reduxreact-hookslocal-storageredux-toolkit

How to use hook in createSlice of react redux


How to use hooks to save data in localStorage in createSlice of react @reduxjs/toolkit When ever I change the theme I want to save the data in localStorage. I know this can done directly with js code with I am having issue with useLocalStorage hook.

import { createSlice } from "@reduxjs/toolkit";
import useLocalStorage from "../hooks/useLocalStorage";

const initialState = {
    theme: true
}

const [settings, setSettings] = useLocalStorage("settings", initialState);


export const settingsSlice = createSlice({
    name: "theme",
    initialState: { value: initialState },
    reducers: {
        setSettings: (state, action) => {
            state.value = action.payload;
        },
        toggleTheme: (state) => {
            const temp = { ...state.value, theme: !state.value.theme };

            //save in localStorage
            setSettings(temp);

            state.value = temp;
        },
    },
});

export const { toggleTheme } = settingsSlice.actions;

export default settingsSlice.reducer;
import { useState } from "react";

function useLocalStorage(key, initialValue) {
    const [storedValue, setStoredValue] = useState(() => {
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : initialValue;
        } catch (error) {
            console.log(error);
        }
    });

    const setValue = (value) => {
        try {
            window.localStorage.setItem(key, JSON.stringify(valueToStore));
        } catch (error) {
            console.log(error);
        }
    };

    return [storedValue, setValue];
}

export default useLocalStorage;

enter image description here

I tried to call the hook before updating my data but I got error


Solution

  • Multiple things:

    1. Reducers have to be pure functions. That means no side effects like reading data from anywhere except from store and action and no writing data anywhere, too. You are not allowed to use localStorage from a reducer.

    2. Hooks can only be called from React components - not any function outside of one. The good thing is that if you do not want a component-local state "synced" with your local store (here you don't), all your code here boils down to window.localStorage.setItem(key, JSON.stringify(valueToStore)); - you don't need the useState stuff here.

    3. Most people just use redux-persist to save a copy of state to localStorage and restore that. It is highly configurable, so you can also only save a portion of it.

    4. If you want to do it by hand, you need to use some kind of middleware (since that is where side effects belong in Redux) - I would recommend using the listener middleware of RTK to look for store changes and saving in a listener middleware effect.