You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux useSelector返回undefined但状态已设置的问题求助

Redux useSelector获取用户名/Token返回undefined问题

我正在开发Twitter(X)复刻项目,采用Redux进行状态管理,通过redux-persist实现持久化登录,将用户的用户名和token存储在Redux(遵循最佳实践)及localStorage中。项目包含主页和个人资料页,分别用于展示帖子列表与个人资料页面。

目前遇到的核心问题:在主页和个人资料页使用useSelector获取token与用户名时,返回值为undefined。但通过控制台打印状态、查看Redux DevTools,均显示状态已正确设置,却无法正常获取对应值。我已查阅Stack Overflow上的类似案例,但未找到适配的解决方案。


个人资料页代码

'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

authReducer代码

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;

Store配置代码

'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;

选择器代码

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;

已尝试的解决方法

我曾改写useSelector的调用方式,例如:

const tokenCheck = useSelector((state) => selectAuthToken(state))

但问题仍未解决。


内容的提问来源于stack exchange,提问作者Akk1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:04:57