I've got an authSlice
const authSlice = createSlice({
name: 'authStore',
initialState,
reducers: {
logout(state = initialState) {
return { ...state, isAuthenticated: false };
},
},
extraReducers: (builder) => {
builder.addCase(login.fulfilled, (state, { payload }) => {
state.isAuthenticated = true;
localStorage.setItem('userId', payload.userId);
});
builder.addCase(login.pending, (state) => {
state.isLoading = true;
});
builder.addCase(login.rejected, (state, { payload, error }) => {
if (payload) {
state.loginError = payload;
state.isLoading = false;
} else {
state.loginError = error;
}
});
},
});
and a userSlice
:
const userSlice = createSlice({
name: 'userStore',
initialState,
reducers: {
clearUser(state = initialState) {
return { ...state };
},
},
extraReducers: (builder) => {
builder.addCase(getUser.fulfilled, (state, { payload }) => {
state.user = payload;
state.isLoading = false;
});
builder.addCase(getUser.pending, (state) => {
state.isLoading = true;
});
builder.addCase(getUser.rejected, (state) => {
state.isLoading = false;
});
},
});
I have a few questions about my code:
clearUser()
in userSlice
from authSlice
?authSlice
and the userSlice
?You wouldn't want to dispatch the clearUser
action from the authSlice.
You could call it from an asyncThunk (or normal thunk) instead, but definitely not from a reducer.
Another possibility is that you make the userSlice
have an extra reducer case for the logout
action
// This is assuming that you are exporting the actions from the authSlice
builder.addCase(authActions.logout,(state=initialState)=>({...state}))
Which is based on your clearUser reducer (which wouldn't actually change the state)
If you wanted to reset the state to the initial state, it would be:
builder.addCase(authActions.logout,(state)=>initialState)
I ended up using a combination of Zachary's answer and referencing a SO post here .
To have a logout
function that clears all state with one call, I needed to create a rootReducer
which contained logic to clear the state:
import { AnyAction, combineReducers, Reducer } from '@reduxjs/toolkit';
import auth from './auth/authSlice';
import user from './user/userSlice';
const combinedReducer = combineReducers({
auth,
user,
});
export const rootReducer: Reducer = (state: RootState, action: AnyAction) => {
if (action.type === 'authStore/logout') {
localStorage.clear();
state = {} as RootState;
}
return combinedReducer(state, action);
};
export type RootState = ReturnType<typeof combinedReducer>;
In the authSlice
I then created an empty logout()
reducer:
const authSlice = createSlice({
name: 'authStore',
initialState,
reducers: {
logout: (state) => {
/* declared here, handled in the root reducer: ../rootReducer.ts */
},
}
})
This was finally consumed inside my component, like so:
import React from 'react';
import { useDispatch } from 'react-redux';
import { logout } from '../store/auth/authSlice';
export const Home = () => {
const dispatch = useDispatch();
return <button onClick={() => dispatch(logout())}>Logout</button>;
};
In the case that I needed to do anything async in the logout process, I would have to use a method similar to what Zachary described (with a Thunk) inside my rootReducer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.