I have this asyncThunk action and everything was fine until I put a dispatch
call before sending request. As a result every code after this dispatch
call doesn't work anymore. 'first' goes in log but 'second' no. I don't know why this dispatch
blocks next codes in my asyncThunk function.
My slice file:
export const postLoginData = createAsyncThunk(
'login/postLoginData',
async (allData) => {
const { dispatch, params } = allData;
let loginResponse = '';
console.log('first')
dispatch(setStatus({type: 'loading', payload: 'wait'}))
console.log('second')
await postRequest('/o/token/coach', params)
.then(response => {
loginResponse = response.data
const data = response.data;
if (data.access_token) {
dispatch(loginSuccess(data))
localStorage.setItem('Authentication', JSON.stringify(data));
}
})
.catch(err => {
if (err.response.status === 400) {
loginResponse = { error: '400 Error' }
}
})
dispatch(setStatus({ type: 'loading', payload: false }))
console.log(loginResponse)
return loginResponse
}
)
You really should use the dispatch
function available on the thunkApi
, the second argument passed to the createAsyncThunk
payload creator.
It's also a bit of a Javascript anti-pattern to mix async/await
with Promise chains; select one or the other.
Basic Example:
export const postLoginData = createAsyncThunk(
'login/postLoginData',
async ({ params }, thunkApi) => {
let loginResponse = '';
thunkApi.dispatch(setStatus({ type: 'loading', payload: 'wait' }));
try {
const { data } = await postRequest('/o/token/coach', params);
loginResponse = data;
if (data.access_token) {
thunkApi.dispatch(loginSuccess(data));
localStorage.setItem('Authentication', JSON.stringify(data));
}
} catch(err) {
if (err.response.status === 400) {
loginResponse = { error: '400 Error' };
}
}
thunkApi.dispatch(setStatus({ type: 'loading', payload: false }));
return loginResponse;
}
);
Since you are using Redux-Toolkit and createAsyncAction
you are kind of missing the point by manually dispatching the setStatus
and loginSuccess
actions to manage any "loading" and "authentication" states when you really ought to be adding reducers cases that handle the dispatched postLoginData.pending
, postLoginData.fulfilled
, and postLoginData.rejected
actions that automagically get dispatched when you dispatch postLoginData
to the store and the action processes.
Here's a suggested refactor:
export const postLoginData = createAsyncThunk(
'login/postLoginData',
async ({ params }, thunkApi) => {
try {
const { data } = await postRequest('/o/token/coach', params);
if (data.access_token) {
localStorage.setItem('Authentication', JSON.stringify(data));
}
return data;
} catch(error) {
return thunkApi.rejectWithValue(error.response.message);
}
}
);
The status slice, add reducer cases to handle the .pending
, and .fulfilled
and .rejected
actions.
const statusSlice = createSlice({
name: "status",
initialState: {
status: false,
},
extraReducers: builder => {
builder
....
.addCase(postLoginData.pending, (state) => {
state.status = "wait";
})
.addCase(postLoginData.fulfilled, (state) => {
state.status = false;
})
.addCase(postLoginData.rejected, (state) => {
state.status = false;
})
....;
},
});
The auth slice, add a reducer case to handle the .fulfilled
action.
const authSlice = createSlice({
name: "auth",
initialState: {
....
},
extraReducers: builder => {
builder
....
.addCase(postLoginData.fulfilled, (state, action) => {
// update whatever state with the fetched data in action.payload
})
....;
},
});