How can I access state of another slice in redux with redux-toolkit?
Asked Answered
N

7

41

In my Redux store I have multiple slices and I would like to access the lang state of the settingsSlice inside the speciesSlice.

Here is a code sample of my slices:

const settingsSlice = createSlice({
  name: 'settings',
  initialState: { lang: 'en', theme: 'dark' },
  reducers: {
    ...
  },
});

const speciesSlice = createSlice({
  name: 'species',
  initialState: data[`vds-list-${HERE I WANT TO USE THE "lang" STATE OF THE SETTINGSSLICE}`],
  reducers: {
    ...
  },
});

Thus far I haven't found a solution so maybe it's just not possible?

I could just use one slice with all of the state inside of there, but I'd really like to separate different parts of the state in different slices.

Naamana answered 18/6, 2020 at 13:38 Comment(2)
If you only use the settings default state then why not define { lang: 'en', theme: 'dark' } as a constant and use that constant?Springfield
@Springfield the state of the settingsSlice changes over time. It adapts to the users system language or the overridden setting.Naamana
A
28

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.

See the Redux FAQ entry on "how can I share state between reducers?" for more details.

Adele answered 18/6, 2020 at 14:23 Comment(0)
C
11

I've managed to achieve this by simply importing the redux store object and have called getState() method.

so in speciesSlice reducer action you can do that:

const speciesSlice = createSlice({
  name: 'species',
  initialState: data[`vds-list-${HERE I WANT TO USE THE "lang" STATE OF THE SETTINGSSLICE}`],
  reducers: {
    ...
    setLang: (state, _) => {
      const reduxStore = store.getState();
      const lang = reduxStore.settingsSlice.lang;
      state = data[`vds-list-${lang}`];
    },
    ...
  },
});
Carpio answered 4/4, 2022 at 22:13 Comment(8)
Would this be considered bad practice / anti pattern?Herald
@DrorBar No, I guess not, there are multiple mentions of the same methodology in redux documentations as wellCarpio
@Dror Personally I would consider it an anti-pattern to avoid. It seems like the reducer in this example doesn’t really do anything and can easily be replaced with a selector (that selects the active language and returns the corresponding data).Chase
@BiskremMuhammad Could you cite/link to the part of the documentation where importing a store and working with it directly is mentionedCards
@GabrielPetersson.. here is the api reference, see the examples.Carpio
@BiskremMuhammad it's an example for how selectors work, nowhere do they recommend importing the store into your reducer redux.js.org/faq/…Cards
This does not work, I get the error "You may not call store.getState() while the reducer is executing. The reducer has already received the state as an argument. Pass it down from the top reducer instead of reading it from the store."Aldwon
You cannot and must not import the store into a reducer file, or try to call store.getState() in a reducer! This is explicitly forbidden and will throw an error.Adele
Y
9

We can do it by adding extraReducers to respond to the action

// Slice A - sliceA.js
export const sliceAinitialState = {
  lang: 'en',
}
const sliceA = createSlice({
  name: 'A'
  initialSlice: sliceAinitialState,
  reducers: {
    langChangedAtSliceA: (state, action) => state.lang = action.payload,
  }
})
export const {langChangedAtSliceA } = sliceA.actions

// Slice B - sliceB.js
import {sliceAinitialState, langChangedAtSliceA} from 'sliceA.js'
const sliceB = createSlice({
  name: 'B'
  initialSlice: {
    lang: sliceAinitialState.lang
  },
  extraReducers: (builder) => {
    builder.addCase(langChangedAtSliceA, (state, action) => {
      state.lang = action.payload
    })
  }
})
Yielding answered 11/3, 2023 at 20:36 Comment(0)
E
5

As referenced in the Redux FAQ entry, "How do I share state between two reducers?", you can use redux-thunk to write a reducer that can access the entire state. For example:

const speciesSlice = createSlice({
  name: 'species',
  initialState: data[`vds-list-${HERE I WANT TO USE THE "lang" STATE OF THE SETTINGSSLICE}`],
  reducers: {
    ...
    internalSetLang: (state, action) => {
      state = data[`vds-list-${action.payload}`];
    },
    ...
  },
});

const { internalSetLang } = speciesSlice.actions;

export function setLang() {
  return (dispatch, getState) => {
    const lang = getState().settings.lang;
    dispatch(internalSetLang(lang));
  };
}

This is similar to @Biskrem Muhammad's answer but avoids having to use the Redux store as a global variable.

Exceed answered 11/11, 2022 at 16:7 Comment(0)
V
0

There is a specific createDraftSafeSelector function available in redux-toolkit for that usage.

Vatic answered 7/3, 2023 at 12:34 Comment(0)
Z
0

If you're familiar with Redux Thunk then this should be easy. Redux Toolkit integrates by default Thunk configuration which is ready to use.

To make an async call basically you need to pass dispatch, moreover getState is on your hand to retrieve any information from the store state !

For example, I've two slices category and main, and here I need to fetch categories but this depends on main slice state property called isOffline

export const fetchCategories = () => (dispatch, getState) => {
  dispatch(handleLoad(true));
  const {isOffline} = getState().main;

  if (isOffline) {
    setTimeout(async () => {
      const categories = await getDataObject('categories');
      dispatch(fetchCategoriesSuccess(categories ?? []));
      dispatch(handleLoad(false));
    }, 1000);

    return false;
  }
};
Zamudio answered 9/5, 2024 at 10:33 Comment(0)
H
-1

It is not necessary to hard code.
If you want to use a data from X slice in Y slice, all you have to do is export the initial state of X slice and import it in Y slice, so that whenever the X slice state changes, it will automatically change it in Y slice also.

Harod answered 29/1, 2024 at 20:20 Comment(2)
Please elaborate. Try for How to Answer.Remount
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Caffeine

© 2022 - 2025 — McMap. All rights reserved.