Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to access global state in createSlice?

Here is an example:

const user = createSlice({
  name: 'user',
  initialState: { name: '', age: 20 },
  reducers: {
    setUserName: (state, action) => {
      state.name = action.payload // mutate the state all you want with immer
    }
  },
  // "map object API"
  extraReducers: {
    [counter.actions.increment]: (state, action) => {
      state.age += 1
    }
  }
})

Can I get access to the counter state? Let's say I want to increment age only when the counter is 30. Otherwise, I would need to listen when the count is changing in useEffect hook and dispatch some action that will handle age increment (?).

In other words, what's the best way to compute the slice of state based on the current global state using redux-toolkit?

like image 465
karolis2017 Avatar asked Mar 18 '20 12:03

karolis2017


2 Answers

This is covered in the Redux FAQ entry on sharing state between reducers.

Pasting the key points:

  • If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.
  • You may need to write some custom functions for handling some of these actions. This may require replacing combineReducers with your own top-level reducer function. You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.
  • Async action creators such as redux-thunk have access to the entire state through getState(). An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice.
like image 69
markerikson Avatar answered Oct 21 '22 23:10

markerikson


I think you could use thunkAPI and extrareducers like below, assuming that you have an auth slice which has the current user object:

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import ordersService from "./ordersService";

const initialState = {
    orders: [],
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: "",
};

//get orders
export const getOrders = createAsyncThunk(
    "orders/getOrders",
    async (__, thunkAPI) => {
        try {
            const userId = thunkAPI.getState().auth.user.id
            return await ordersService.getOrders(userId);
        } catch (error) {
            const message =
                (error.response &&
                    error.response.data &&
                    error.response.data.message) ||
                error.message ||
                error.toString();
            return thunkAPI.rejectWithValue(message);
        }
    }
);

export const ordersSlice = createSlice({
    name: "orders",
    initialState,
    reducers: {
        reset: (state) => {
            state.isError = false;
            state.isSuccess = false;
            state.isLoading = false;
            state.message = "";
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(getOrders.pending, (state) => {
                state.isLoading = true;
            })
            .addCase(getOrders.fulfilled, (state, action) => {
                state.isLoading = false;
                state.isSuccess = true;
                state.orders = action.payload;
            })
            .addCase(getOrders.rejected, (state, action) => {
                state.isLoading = false;
                state.isError = true;
                state.message = action.payload;
                state.orders = [];
            });
    },
});

export const { reset, setOrder } = ordersSlice.actions;
export default ordersSlice.reducer;
like image 2
SalemFeyzo Avatar answered Oct 21 '22 23:10

SalemFeyzo