search

Home  >  Q&A  >  body text

Taking action within actions: Leverage nested actions to make a difference in your next Redux

I want to implement the logic of authorizing users when the page loads. Initially, I wanted to check if there is a token in the cookie (checkUserToken) and if there is or not - call another function (fetchUserData) which will make a future request to the server. Finally, when the server responds - the third function (setUserData) is called which will populate userData

with the user data
'use client'

import { createSlice } from "@reduxjs/toolkit";
import { getCookie } from '@/app/untils/Cookies';

const initialState = {
  userData: null
}

export const userSlice = createSlice({
  name: "userData",
  initialState,
  reducers: {
    checkUserToken: ()  => {
      console.log('chekc')
      const token = getCookie('user-token');
      console.log(token)
      if (token)
        return fetchUserData(token)
      else
        return fetchUserData(false)
    },
    fetchUserData: async (state, action) => dispatch => {
      return  console.log('FETCH')
      // console.log(state)
      // console.log(action)
    },
    setUserData: (state, action) => {
      console.log('SET USER')
      console.log(action)
      console.log(state)
    }
  }
})

export const { checkUserToken, fetchUserData, setUserData } = userSlice.actions

export default userSlice.reducer

How can I implement similar functionality in my slice?

P粉614840363P粉614840363436 days ago486

reply all(1)I'll reply

  • P粉459440991

    P粉4594409912023-09-18 00:41:32

    Reducer functions are pure functions, they do not perform side effects like dispatching actions. checkUserToken cannot dispatch any actions, fetchUserData cannot return function values. It seems to me that checkUserToken and fetchUserData are actually asynchronous actions. Create a thunk action for them.

    Example:

    import { createSlice, createAsyncAction } from "@reduxjs/toolkit";
    import { getCookie } from '@/app/untils/Cookies';
    
    export const checkUserToken = createAsyncAction(
      "userData/checkUserToken",
      (_, thunkAPI) => {
        console.log('check');
        const token = getCookie('user-token');
        console.log(token);
        
        return thunkAPI.dispatch(fetchUserData(token ?? false));
      },
    );
    
    export const fetchUserData = createAsyncAction(
      "userData/fetchUserData",
      async (token, thunkAPI) => {
        try {
          console.log('FETCH');
          ... 异步获取逻辑 ...
          return /* 一些数据??? */
        } catch(error) {
          return thunkAPI.rejectWithValue(error));
        }
      },
    );
    
    const initialState = {
      userData: null,
    };
    
    export const userSlice = createSlice({
      name: "userData",
      initialState,
      reducers: {
        setUserData: (state, action) => {
          console.log('SET USER');
          ....
        }
      },
      extraReducers: builder => {
        builder
          .addCase(fetchUserData.fulfilled, (state, action) => {
            // 使用返回的 action.payload 值更新用户数据
          })
          .addCase(fetchUserData.rejected, (state, action) => {
            // 如有必要,设置任何错误状态
          });
      },
    })
    
    export const { setUserData } = userSlice.actions;
    
    export default userSlice.reducer;
    

    Please note that the fetchUserData action can directly access cookies/tokens, and the fetchUserData.fulfilled reducer case can also set/update user data status. This means that the setUserData and checkUserToken actions may be unnecessary.

    reply
    0
  • Cancelreply