After my redux dispatches the logout
action, I want to reset to my initial state. I’m using nextjs
, and I don’t understand why my desired logout reducer in authenticateSlice.js
doesn’t execute. I was also using a redux-persist
to keep my state persistent.
Here is my code from store.js
import { configureStore } from "@reduxjs/toolkit";
import authenticateSlice from "./slices/authenticateSlice";
import { persistReducer, persistStore } from "redux-persist"; // import persistStore
import storage from "./storage";
import { encryptTransform } from "redux-persist-transform-encrypt";
import { combineReducers } from "redux";
import thunk from "redux-thunk";
const reducers = combineReducers({
auth: authenticateSlice.reducer,
});
let transforms = null;
if (process.env.NODE_ENV === "production") {
const encrypt = encryptTransform({
secretKey: process.env.NEXT_PUBLIC_REDUX_SECRET,
onError: function (error) {
// Handle the error.
},
});
transforms = [encrypt];
}
const persistConfig = {
key: "root",
storage: storage,
transforms,
};
const persistedReducer = persistReducer(persistConfig, reducers);
const store = configureStore({
reducer: persistedReducer,
middleware: [thunk],
});
let persistor = persistStore(store); // initialize persistor
export { store, persistor };
Here is my code from the authenticateSlice.js
which I have the logout
function to dispatch.
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { commonPostRequest } from "@/django-api/common/commonRequestAPI";
import { CommonPostHeader } from "@/django-api/common/commonHeadersAPI";
export const fetchUserLogin = createAsyncThunk(
"auth/login",
async (arg, { rejectWithValue }) => {
const { username, password } = arg;
try {
const loginRequest = await commonPostRequest({
body: { username: username, password: password },
headers: CommonPostHeader,
url: "http://localhost:8000/api/accounts_app/login",
});
if (loginRequest.data) {
return loginRequest.data;
} else {
throw new Error(loginRequest.message);
}
} catch (err) {
return rejectWithValue(err.message);
}
}
);
export const logout = () => {
return { type: "auth/logout" };
};
// loading: 'idle' | 'pending' | 'succeeded' | 'failed'
const initialState = {
data: {},
loading: "idle",
message: "",
};
const authenticateSlice = createSlice({
name: "auth",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUserLogin.pending, (state) => {
state.loading = "pending";
})
.addCase(fetchUserLogin.fulfilled, (state, action) => {
state.loading = "succeeded";
state.data = action.payload;
})
.addCase(fetchUserLogin.rejected, (state, action) => {
state.loading = "failed";
state.message = action.payload;
})
.addCase(logout, (state) => {
Object.assign(state, initialState);
});
},
});
export default authenticateSlice;
Lastly, here is my Header
function component where I want to dispatch the logout
action from slice or dispatch the logout function to return with my initial state.
import { Typography } from "@mui/material";
import { Row, Col, Divider, notification } from "antd";
import styles from "./Header.module.scss";
import Image from "next/image";
import Link from "next/link";
import {
toLocalZoneDateTime,
getCurrentDateTimeStamp,
} from "../common/functions/datetime";
import { useDispatch } from "react-redux";
import { useRouter } from "next/router";
import { logout } from "../../next-redux/slices/authenticateSlice";
const Header = (props) => {
const dispatch = useDispatch();
const { user } = props;
const router = useRouter();
const currentDateTimeStamp = getCurrentDateTimeStamp();
const handleLogoutClick = (e) => {
e.preventDefault();
console.log("logout");
dispatch(logout());
};
return (
<>
<Row>
<Col span={24}>
<Row gutter={[8, 8]} className={styles.topBar}>
<Col span={12}>
<Typography variant="subtitle2" className={styles.topDate}>
{toLocalZoneDateTime(currentDateTimeStamp)}
</Typography>
</Col>
<Col span={12}>
{user ? (
<Typography align="right">
<a
onClick={(e) => {
handleLogoutClick(e);
}}
className={styles.topBarLinks}
>
Logout
</a>
</Typography>
) : (
<>
<Typography align="right">
{" "}
<Link href="/signin/" className={styles.topBarLinks}>
Sign-in
</Link>{" "}
<Link href="/signup/" className={styles.topBarLinks}>
Sign-up
</Link>
</Typography>
</>
)}
</Col>
</Row>
</Col>
</Row>
</>
);
};
export default Header;
2
Answers
You are using redux persist so you have to logout in different way.
Issue
logout
is a function, not an action object, so the extra reducer case isn’t running.Solution
The solution would be to declare
logout
as a created action via thecreateAction
utility.Or declare a
logout
reducer case which will generate thelogout
action that could be exported.