4

How could you replace the state of a store consisting of multiple slices with some other, new state in react using redux toolkit?

You can revert the whole store to its initial state using extraReducers: could the same mechanism be used to change the store state to something else then the initial state?

For example, you would have something like this:

const aSlice = createSlice({ 
  name: 'a', 
  initialState: {a: 1}, 
  reducers: {
    someReducer(state, action) {...}
  }
})
const bSlice = createSlice({ 
  name: 'b', 
  initialState: {b: 'foo'}, 
  reducers: {}
})

const store = configureStore({
  reducer: {
    aReducer: aSlice.reducer,
    bReducer: bSlice.reducer,
  }
});

export type RootState = ReturnType<typeof store.getState>

In a react component you can update the state with:

const dispatch = useDispatch();
dispatch(someReducer({...}));

How would you replace the state of the whole store with something like this:

{
  "aReducer": {"a": 2},
  "bReducer": {"b": "bar"},
}
Blee
  • 419
  • 5
  • 11

3 Answers3

5

You can indeed use extraReducers with typesafety, as suggested by dermeck.

A minimal example would be:


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

export const replaceWith = createAction<RootState>('REPLACE_WITH');


const initialState: { a: number } = {
  a: 0
}

export const aSlice = createSlice({
  name: 'a-slice',
  initialState,
  reducers: {
    reduce(state, action: PayloadAction<number>) {
      return {a: action.payload}
    }
  },
  extraReducers: (builder) => {
    builder.addCase(replaceWith, (_, action) => {
      return {
        ...action.payload.aReducer,
      };
    });
  },
});

export const bSlice = createSlice({
  name: 'b-slice',
  initialState: {},
  reducers: {/* TODO */},
  extraReducers: (builder) => {/* TODO */},
});

const rootReducer = combineReducers({
  aReducer: aSlice.reducer,
  bReducer: bSlice.reducer
});

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

export type RootState = ReturnType<typeof rootReducer>;

And finally, in your React component, you can do something like:

const dispatch = useDispatch();
dispatch(replaceWith(newState));
Blee
  • 419
  • 5
  • 11
2

You can use extraReducer for that.

You can pass an arbitrary payload (like {"a": 2, "b": "bar"} to the created action. With createAction you can have actions which don't "belong" to a specific slice, see: https://redux-toolkit.js.org/api/createAction and implement extraReducers in both slices which only use their part of the payload.

dermeck
  • 131
  • 5
  • This would work but it is not typesafe, because you don't know the RootState type after the `createStore`: `const replaceWith = createAction('REPLACE_WITH')`, and adding to each slice: `extraReducers: (builder) => builder.addCase(replaceAll, (state: action) => action.payload.xReducer)`. How would you make it typesafe? – Blee Oct 20 '22 at 06:42
  • You can get the RootState type by defining the rootReducer and exporting its ReturnType as described here https://redux-toolkit.js.org/usage/usage-with-typescript#getting-the-state-type After that you can do domething like this: `export const myAction = createAction('MyActionType');` – dermeck Oct 20 '22 at 07:05
  • But, as in the example, you have to define `myAction` first, because you want to use that when creating your slices, with which you finally create your rootReducer (and RootState). How could you use RootState while defining `myAction`? – Blee Oct 20 '22 at 07:27
  • Hm, yeah that sounds like it shouldn't work. I had a similar use case where this approach worked without TypeScript complaining. But maybe I just accidentally loose type safety somewhere on the way, so I'm not sure if that's what you are looking for. But if you're curious the code is here: https://github.com/dermeck/feeds-sidebar/blob/rootstate-refactor/src/store/actions.ts#L7 . – dermeck Oct 20 '22 at 07:57
1

Reducers, by definition, only have access to the section of state that they own. So, if I have {users: usersReducer, posts: postsReducer}, the usersReducer has no access to the posts state slice at all. How can I access state of another slice in redux with redux-toolkit?.

So you have to dispatch two actions of two slices and every individual reducer will update its state individually.

Arifur Rahaman
  • 534
  • 1
  • 2
  • 8
  • I think this would be possible with extraReducers, which allow to respond to other action types besides the types it has generated ([docs](https://redux-toolkit.js.org/api/createSlice#extrareducers)). But what would such an action look look like? – Blee Oct 20 '22 at 06:08