I'm rather new to the whole React & Redux ecosystem & am trying to understand when & why to use extra reducers vs directly dispatching actions within an async thunk when working with the Redux toolkit.
Probably best explained with an example showing both solutions:
auth.slice.ts
// ...
export const login = createAsyncThunk<LoginResponse, LoginData>(
'auth/login',
async ({ email, password }, thunkAPI) => {
const data = await AuthService.login(email, password);
// Extract user info from login response which holds other information as well
// in which we're not interested in the auth slice...
const userInfo = loginResponseToUserInfo(data);
LocalStorageService.storeUserInfo(userInfo);
// Return the whole login response as we're interested in the other data
// besides the user info in other slices which handle `login.fulfilled` in
// their own `extraReducers`
return data;
}
);
// ...
const authSlice = createSlice({
// ...
extraReducers: builder => {
builder.addCase(login.fulfilled, (state, { payload }) => {
// Again: Extract user info from login response which holds other
// information as well in which we're not interested in the auth slice...
const userInfo = loginResponseToUserInfo(payload);
return { ...state, userInfo };
}))
// ...
},
});
// ...
auth.slice.ts
// ...
export const login = createAsyncThunk<LoginResponse, LoginData>(
'auth/login',
async ({ email, password }, thunkAPI) => {
const data = await AuthService.login(email, password);
// Extract user info from login response which holds other information as well
// in which we're not interested in the auth slice...
const userInfo = loginResponseToUserInfo(data);
LocalStorageService.storeUserInfo(userInfo);
// !!! Difference to version 1 !!!
// Directly dispatch the action instead of using `extraReducer` to further
// process the extracted user info
thunkAPI.dispatch(authSlice.actions.setUserInfo(userInfo));
// Return the whole login response as we're interested in the other data
// besides the user info in other slices which handle `login.fulfilled` in
// their own `extraReducers`
return data;
}
);
// ...
const authSlice = createSlice({
// ...
reducers: {
setUserInfo: (state, { payload }: PayloadAction<UserInfo>) => ({
...state,
userInfo: payload,
}),
// ...
},
});
// ...
If I'm not completely wrong, both examples do the exact same thing but looking through the internet I mostly find people suggesting option 1 using the extraReducer
which is why I'm asking:
extraReducers
approach"?loginResponseToUserInfo
in 2 places (the async thunk & the extraReducer
) whilst I only need to call it once in the 2nd version...In my opinion both are valid although I would go for #1 personally.
To justify my choice :