In the process of developing a project that mirrors Twitter(X), my approach involves implementing state management with REDUX and maintaining persistent login using redux-persist. I am storing the user's username and token in both the Redux store (for best practices) and local storage. The project consists of various pages, most notably home and profile. Home displays the user's profile page while Profile renders the PostList. However, I have encountered an issue when using useSelector on the Home and Profile pages. Despite attempts to retrieve the token from the state using useSelector, it consistently returns undefined, which also happens with the username. Although thorough checks through console logging the state and reviewing Redux DevTools indicate that the state is correctly receiving the values, I am unable to retrieve them for unknown reasons.
Despite exploring similar cases on Stack Overflow, none of the solutions provided seem to solve this particular problem.
Below is the code snippet for the Profile page:
'use client'
import { IconButton, Typography, Avatar, Button } from '@mui/material'
import React from 'react'
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Link from 'next/link';
import Image from 'next/image';
import moment from 'moment';
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import ProfileHeaderCategories from '../components/ProfileHeaderCategories';
import { selectAuthToken,selectAuthUser } from '../store/selectors/authSelectors';
import { useSelector } from 'react-redux';
let registrationDate = moment().format('[Joined] MMMM Do YYYY').toString()
const backgroundImageUrl = "/"
const Profile = () => {
const username = useSelector(selectAuthUser);
const token = useSelector(selectAuthToken)
console.log(username, token) // returns undefined
return (
<main className='border-r-[0.5px] border-r-gray-600 w-[600px] max-w-[650px]'>
<div className='flex items-center pl-2 mb-2'>
<Link href="/home">
<IconButton sx={{
padding: 1,
marginTop: 1,
}}
className='hover:bg-[#293640] mr-4'
>
<ArrowBackIcon
className='text-white rounded-full text-[20px] font-bold'
/>
</IconButton>
</Link>
<Typography variant="h6" className='font-bold'>
{username}
</Typography>
</div>
<Image src={backgroundImageUrl} alt="Background Profile pic" width={500} height={500} />
<div className='flex justify-between'>
<Avatar sx={{
width: 120,
height: 120,
position: 'absolute',
transform: 'translateY(-50%)',
marginLeft: 2,
}}
className='border-4 border-[#15202b]' />
</div>
<Button className='text-white font-bold bg-[15202b] rounded-full border-gray-600 capitalize float-right'
sx={{
border: 0.5,
borderColor: "gray",
marginTop: 1,
marginRight: 1,
padding: 1,
}}
>Edit profile</Button>
<div className='flex flex-col mt-16'>
<span className='px-4 font-bold text-xl'>{`Your name`}</span>
<span className='text-gray-400 text-base px-4'>{username}</span>
<div className='text-base text-gray-400 pt-4 px-4 mb-4'>
<CalendarMonthIcon sx={{
fontSize: 'medium',
marginRight: 1,
}} />
{registrationDate}
</div>
</div>
<div className='border-b-[0.5px] border-b-slate-500'>
<ProfileHeaderCategories />
</div>
</main>
)
}
export default Profile
Code for authReducer and store // separate files:
import { createSlice } from '@reduxjs/toolkit';
const authReducer= createSlice({
name: 'auth',
initialState: {
username: null,
token: null,
showSignIn: true,
},
reducers: {
setUsername: (state, action) => {
console.log('Before set name:', state.username);
state.username = action.payload;
console.log('After set name:', state.username);
},
setToken: (state, action) => {
console.log('Before setting token:', state.token);
state.token = action.payload;
console.log('After setting token:', state.token);
},
logout: (state) => {
state.username = null;
state.token = null;
localStorage.clear()
},
toggleShowSignIn: (state) => {
console.log('Before toggle:', state.showSignIn);
state.showSignIn = !state.showSignIn
console.log('After toggle:', state.showSignIn);
}
}
});
export const { setUsername, setToken, logout, toggleShowSignIn } = authReducer.actions;
export default authReducer.reducer;
'use client'
import { configureStore, combineReducers } from "@reduxjs/toolkit";
import postSlice from "./slices/postSlice";
import signUpReducer from "./reducers/signUpReducer";
import signInReducer from "./reducers/signInReducer";
import authSlice from "./slices/authSlice";
import storage from 'redux-persist/lib/storage';
import { PersistPartial } from "redux-persist/es/persistReducer";
import {
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
// RootState type to include persisted state
export type RootState = ReturnType<typeof rootReducer> & PersistPartial;
const persistConfig = {
key: 'signData',
storage,
whitelist: ['auth'],// only the 'auth' reducer in persisted state
};
// Combine reducers
const rootReducer = combineReducers({
posts: postSlice,
signUpForm: signUpReducer,
signIn: signInReducer,
auth: authSlice,
});
// Create persisted reducer
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
})
})
export default store;
Code for selectors:
import { RootState } from "../store";
export interface UsernameAuth {
username: string
}
export interface TokenAuth {
token: string
}
export const selectAuthUser = (state: UsernameAuth) => state.username;
export const selectAuthToken = (state: TokenAuth) => state.token;
export const selectShowSignIn = (state: RootState) => state.auth.showSignIn;
Attempting to modify the useSelector function by utilizing a different syntax like: const tokenCheck = useSelector((state) => selectAuthToken(state)) did not yield any results.