如何从 redux 工具包异步 thunk 的挂起状态修改另一个切片的状态

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

我正在构建一个简单的应用程序。我正在使用 redux 工具包进行状态管理

它必须查询数据库以检查用户是否已通过身份验证。

如果是,它会为用户设置姓名、电子邮件等

在检查数据库时,我想在前端加载一个微调器,微调器占据整个屏幕,并会在数据库查询时随时显示。出于这个原因,我想要一个单独的应用程序状态,它有两个值,即加载和错误

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)
    });
  },
});

您可以在不同的状态片中处理一个动作。您应该在 appSliceuserSlice 文件中引用 authenticateUser.pendingauthenticateUser.rejected 动作创建者,并在 appSliceextraReducers 中处理它们。

例如,如果 user/authenticate 操作因错误而失败。

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());
});

输出:

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