I want to implement the logic to authorize the user when the page loads. Initially, I wanted to check if the token was in the cookies (checkUserToken
) and if it was or was not - call another function (fetchUserData
), which in the future would make a request to the server. Finally, when the server responded - call a third function (setUserData
), which would fill userData
with 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 something like this in my slice?
Reducer functions are pure functions, they don't do side-effects like dispatching actions. checkUserToken
can't dispatch any actions, and fetchUserData
can't return a function value. It appears to me that checkUserToken
and fetchUserData
are actually asynchronous actions. Create a thunk action for these.
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');
... asynchronous fetching logic ...
return /* some data??? */
} 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) => {
// update the user data with returned action.payload value
})
.addCase(fetchUserData.rejected, (state, action) => {
// set any error state, if necessary
});
},
})
export const { setUserData } = userSlice.actions;
export default userSlice.reducer;
Note that it would be trivial for the fetchUserData
action to access the cookies/token directly, and that the fetchUserData.fulfilled
reducer case can set/update the user data state as well. This means that setUserData
and checkUserToken
actions are likely unnecessary.