Reset state to initial with redux-toolkit
Asked Answered
S

9

89

I need to reset current state to initial state. But all my attempts were unsuccessful. How can I do it using redux-toolkit?

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState: {
    returned: [],
  },
  reducers: {
    reset(state) {
      //here I need to reset state of current slice
    },
  },
});

Surratt answered 20/12, 2019 at 11:25 Comment(1)
@AjeetShah perfect solution, thanks for sharing it.Anallese
S
162

Something like this:

const intialState = {
  returned: []
}

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState,
    reducers: {
        reset: () => initialState
    }
});
Stjohn answered 20/12, 2019 at 16:5 Comment(9)
yes, it works. Also correct is reset() {return initialState} or reset: () => initialStateSurratt
I thought just setting state = initialState would suffice because in other examples, we only need to mutate state. Alas, resetting the state needed a different approach :/Marrero
I must admin that even redux-toolkit is awesome it is littlebit immutability dark-magic :D Btw return { ...initialState } also works...Crumpton
Thanks for the tip. Returning the value did it. I wasted some time by assigning initialState to the state by assuming that immer would do the magic underneath!Ferriferous
Year later got the notification, which made me curious if my answer became obsolete :) I have prepared a small demo which clearly shows that provided answer is still perfectly valid and works with the latest redux-toolkit, please check it here: codesandbox.io/s/initial-state-redux-toolkit-12d1-9lpu7?file=/…Stjohn
@dorklord yeah, why isn't state = initialstate sufficient?Hawkie
Also the state => initialState doesn't need the state in it. As the second answer shows, () => initialState sufficesDroppings
@Marrero state = initialState doesn't work because you are changing the reference and redux toolkit has no way of knowing that as it keeps the old reference. You must either mutate the original state OR return new object. @Hawkie @DroppingsFlounce
@Crumpton return { ...initialState } is unnecessary and perhaps you come from traditional redux where mutation was forbidden. Here return initialState and return { ...initialState } are equivalent.Flounce
E
22

When using multiple slices, all slices can be reverted to their initial state using extraReducers.

First, create an action that can be used by all slices:

export const revertAll = createAction('REVERT_ALL')

In every slice add an initialState, and an extraReducers reducer using the revertAll action:

const initialState = {};
export const someSlice = createSlice({
  name: 'something',
  initialState,
  extraReducers: (builder) => builder.addCase(revertAll, () => initialState),
  reducers: {}
});

The store can be created as usual:

export const store = configureStore({
  reducer: {
    someReducer: someSlice.reducer,
  }
})

And in your react code you can call the revertAll action with the useDispatch hook:

export function SomeComponent() {
  const dispatch = useDispatch();

  return <span onClick={() => dispatch(revertAll())}>Reset</span>
}
Enthymeme answered 27/9, 2022 at 7:59 Comment(8)
Wow! That's what I've been looking for!Reductase
This code works though we need to add repititive code in all the reducers. Wish there was a more elegant way to achieve without duplication of codeThursby
Thanks! Suggestions on removing the repetition are welcomeEnthymeme
This is the only way worked in 2023. Thanks.Vanir
Thanks @Blee. Please I need clarification on how to do the dispatch. Since we have the rever All on all slices. How do I combine all before dispatching?Shuttlecock
That is what extraReducers do: they allow all the slices to respond to the same action. The dispatch works like any other dispatch, but now it triggers multiple reducers.Enthymeme
This is the best way in 2023. Thanks mate, you saved my dayBrote
This results in typeOrActionCreator is undefined for meProfiteer
C
18

This worked for me (mid-late 2020). Formatted with your code context as an example.

const initialState = {
  returned: [],
};

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState,
  reducers: {
    reset: () => initialState,
  },
});

Casiecasilda answered 12/8, 2020 at 19:1 Comment(2)
None of these worked for me :( it just says initialState is not defined. My bad forgot to define the initialstateCannonade
This is the better styled answer.Ambrosia
C
13

Replacing state with initialState directly did not work for me (mid 2020). What I finally got working was to copy each property over with Object.assign(). This worked:

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState: {
        returned: []
    },
    reducers: {
        reset(state) {
            Object.assign(state, initialState)
        }
    }
});
Cyclamen answered 17/7, 2020 at 16:12 Comment(2)
Can you please answer my question #63885639Rosabella
Thank you sm! Nothing else worked for me!Madiemadigan
W
9

We do it like this guys.

Suppose you want to clear all the data at the point of logging out.

In your store.tsx file:

import { AnyAction, combineReducers, configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice'
import messageReducer from './slices/messageSlice'



const appReducer = combineReducers({
  auth: authReducer,
  message: messageReducer,
});

const reducerProxy = (state: any, action: AnyAction) => {
  if(action.type === 'logout/LOGOUT') {
    return appReducer(undefined, action);
  }
  return appReducer(state, action);
}

export const store = configureStore({
  reducer: reducerProxy,
});

Then you create a thunk like this:

export const logout = createAsyncThunk(
    "auth/logout",
    async function (_payload, thunkAPI) {
        thunkAPI.dispatch({ type: 'logout/LOGOUT' });
        console.log('logged out')
    }
);

After you've dispatched the logout thunk, you can also refresh the browser so it auto-redirects the user to the login page.

function MyReactComponent() {
   const dispatch = useDispatch()

   function myLogoutOnClickHandler() {
      dispatch(logout())
      window.location = window.location;
   }
   ...

}
Wilow answered 16/8, 2022 at 10:23 Comment(0)
F
6

In my case, as the previous answer, mid 2021, just setting the initial state DO NOT WORK, even if you use the toolkit adapter like :

reducers: {
        // Other reducers
         state = tasksAdapter.getInitialState({
                status: 'idle',
                error: null,
                current: null
            })
        }
    },


instead, you should use Object.assign(), guess that it's related with the internal immer library behavior

Fellowship answered 6/3, 2021 at 12:48 Comment(1)
You're right. In v1.5.0 you have to get it done with Object.assign(state, initialState)Diversification
A
3

Try this. In my case, I wanted to return all slices to initialState when a certain action is dispatched.

  • First, let's create action:
import { createAction } from '@reduxjs/toolkit';

export const resetPanelsAction = createAction('resetPanelsData');
  • When creating our store, we save a copy of the initialState in the middleware:
import { Middleware } from '@reduxjs/toolkit';

export const resetDataMiddleware: Middleware =
    ({ getState }) =>
    (next) => {
        // "Caching" our initial app state
        const initialAppState = getState();

        return (action) => {
            // Let's add the condition that if the action is of 
            // type resetData, then add our cached state to its payload
            if (action.type === 'resetData') {
                const actionWithInitialAppState = {
                    ...action,
                    payload: initialAppState,
                };

                return next(actionWithInitialAppState);
            }

            return next(action);
        };
    };
  • Almost done! Now let's change our root reducer a little by adding a wrapper that will check the action type, and if it is equal to resetData, then return combinedReducers with our initialState, which will be in payload.
import { AnyAction } from 'redux';
import { combineReducers } from '@reduxjs/toolkit';

export const combinedReducers = combineReducers({
    /** Your reducers */
});

export const rootReducer = (
    state: ReturnType<typeof combinedReducers> | undefined,
    action: AnyAction,
) => {
    if (action.type === 'resetPanelsData') {
        return combinedReducers(action.payload, action);
    }

    return combinedReducers(state, action);
};
Adaadabel answered 9/12, 2022 at 9:31 Comment(0)
P
0

You can use spread opearator for initialState

const initialState: {
  returned: unknown[] //set your type here
} = {
  returned: []
}

const showOnReviewSlice = createSlice({
  name: 'showOnReview',
  initialState,
  reducers: {
    reset() {
      return {
        ...initialState
      }
    }
  }
});
Paronomasia answered 2/12, 2021 at 11:12 Comment(0)
H
0

You can also reset and change some initial parameters like this:

const intialState = {
  name: "",
  surname: "",
}

const showOnReviewSlice = createSlice({
    name: 'showOnReview',
    initialState,
    reducers: {
        reset: () => initialState, ...initialState.name = "Example"
    }
});
Heat answered 25/11, 2023 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.