简体   繁体   中英

how to modify the state of another slice from pending state of redux toolkit async thunk

I am building a simple application. I am using redux toolkit for state management

It has to query the database to check if user is authenticated.

if yes it sets name,email etc for the user

while it is checking the database I want a loading spinner on the frontend the spinner takes the entire screen and will be shown anytime there a database query. for that reason I want to have a seperate app state that has two values viz loading and error

appSlice

const initialState = {loading : false,error:false,error_msg:null}
export const appSlice = createSlice({
    name : 'app',
    initialState : {value : initialState},
    reducers : {
        toggle : (state,action)=>{
            state.value.loading = action.payload
        }
    },
});

userSlice

const initialState = { name: "", email: "", role: "", isAuthenticated: false };
export const authenticateUser = createAsyncThunk(
  "user/authenticate",
  async () => {
    let res = await axiosInstance.get("/user/authenticate");
    return res.data;
  }
);
export const userSlice = createSlice({
  name: "user",
  initialState: { value: initialState },
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(authenticateUser.pending, (state, action) => {
      //change loading to true for app slice something like (state.app.loading = true)
    });
    builder.addCase(authenticateUser.fulfilled, (state, action) => {
      state.value = action.payload
    });
    builder.addCase(authenticateUser.rejected, (state, action) => {
      //change error to true for app slice something like (state.app.error = true)
      //change error_msg to action.payload for app slice 
      //something like (state.app.error_msg = action.payload)
    });
  },
});

You can handle one action in different state slices. You should reference the authenticateUser.pending and authenticateUser.rejected action creators from the userSlice file in appSlice , and handle them in extraReducers of appSlice .

For example, if the user/authenticate action fails with an error.

import { configureStore, createAsyncThunk, createSlice } from '@reduxjs/toolkit';

export const authenticateUser = createAsyncThunk<any, any, { rejectValue: { error: string } }>(
  'user/authenticate',
  async (_, { rejectWithValue }) => {
    // success
    // return { name: 'teresa teng', email: 'teresa@gmail.com', role: 'admin', isAuthenticated: true };
    // fail
    return rejectWithValue({ error: 'network error' }) as unknown as { error: string };
  },
);
export const userSlice = createSlice({
  name: 'user',
  initialState: { value: { name: '', email: '', role: '', isAuthenticated: false } },
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(authenticateUser.fulfilled, (state, action) => {
      state.value = action.payload;
    });
  },
});

export const appSlice = createSlice({
  name: 'app',
  initialState: { value: { loading: false, error: false, error_msg: '' } },
  reducers: {
    toggle: (state, action) => {
      state.value.loading = action.payload;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(authenticateUser.pending, (state, action) => {
      state.value.loading = true;
    });
    builder.addCase(authenticateUser.rejected, (state, action) => {
      state.value.error = true;
      state.value.error_msg = action.payload?.error || 'unknown error';
    });
  },
});

const store = configureStore({
  reducer: { app: appSlice.reducer, user: userSlice.reducer },
});
store.dispatch(authenticateUser({}));
store.subscribe(() => {
  console.log(store.getState());
});

Output:

{
  app: { value: { loading: true, error: true, error_msg: 'network error' } },
  user: { value: { name: '', email: '', role: '', isAuthenticated: false } }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM