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

MERN+Redux Toolkit认证系统条件渲染异常问题求助

MERN认证系统Redux Toolkit条件渲染异常问题

我用Redux Toolkit构建MERN认证系统,配置看起来正常,但条件渲染功能异常:初始状态下currentUser为null,Login组件本该渲染登录页面,却错误渲染了仅在有用户时才显示的UpdateProfile组件,且Redux DevTools显示currentUser确实为null。

相关代码

1. auth Slice代码

import { createSlice } from "@reduxjs/toolkit";

const authSlice = createSlice({
  name: "auth",
  initialState: {
    currentUser: null,
    isFetching: false,
    error: false,
  },
  reducers: {
    reset: (state) => {
      state.currentUser = null;
      state.isFetching = false;
      state.error = false;
    },

    loginStart: (state) => {
      state.isFetching = true;
    },
    loginSuccess: (state, action) => {
      state.isFetching = false;
      state.currentUser = action.payload;
    },
    loginFail: (state) => {
      state.isFetching = false;
      state.error = true;
    },

    registerStart: (state) => {
      state.isFetching = true;
    },
    registerSuccess: (state, action) => {
      state.isFetching = false;
      state.currentUser = action.payload;
    },
    registerFail: (state) => {
      state.isFetching = false;
      state.error = true;
    },

    logoutSuccess: (state) => {
      (state.currentUser = null),
        (state.isFetching = false),
        (state.error = false);
    },
  },
});

export const {
  reset,
  loginStart,
  loginSuccess,
  loginFail,
  registerStart,
  registerSuccess,
  registerFail,
} = authSlice.actions;
export default authSlice.reducer;

2. store配置代码

import { configureStore } from "@reduxjs/toolkit";
import authReducer from './authRedux'
import storage from 'redux-persist/lib/storage'
import { 
    persistReducer,
    persistStore,
    FLUSH,
    REHYDRATE,
    REGISTER,
    PURGE,
    PERSIST } from 'redux-persist';

const persistConfig={
    key:'root',
    version: 1,
    storage,
}

const persistedReducer = persistReducer(persistConfig, authReducer);

export const store = configureStore({
    reducer:{
        auth: persistedReducer,
    },
    middleware:(getDefaultMiddleware) =>
    getDefaultMiddleware({
        serializableCheck:{
            ignoreActions:[FLUSH,REGISTER,REHYDRATE,PERSIST,PURGE],
        },
    })
});

export let persistor = persistStore(store);

3. Login组件代码

import React, { useState } from "react";
import { Form, Card, Button, Alert } from "react-bootstrap";
import { Link, useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { login } from "../../Redux/apiCalls";
import UpdateProfile from "../UpdateProfile/Updateprofile";

export default function Login() {
  const [username, setUserName] = useState("");
  const [password, setPassword] = useState("");
  const dispatch = useDispatch();
  const currentUser = useSelector((state) => state.auth);
  const { isFetching, error } = useSelector((state) => state.auth);
  const navigate = useNavigate();

  async function handleSubmit(e) {
    e.preventDefault();
    try {
      if(!currentUser){
        navigate('/')
      }else{
        login(dispatch, { username, password });
        navigate('/');
      }
    } catch (error) {
      console.log(error);
    }
  }

  console.log(currentUser);
  return (
    <>
    {currentUser ? (<UpdateProfile/>):(
      <Card className="shadow-lg p-3 mb-2 bg-white rounded">
      <Card.Body>
        <h2 className="text-center mb-4">Log In</h2>
        {error && <Alert variant="danger">{error}</Alert>}
        <Form onSubmit={handleSubmit}>
          <Form.Group id="username">
            <Form.Label>UserName</Form.Label>
            <Form.Control
              type="text"
              required
              onChange={(e) => setUserName(e.target.value)}
            />
          </Form.Group>
          <Form.Group id="password">
            <Form.Label>Password</Form.Label>
            <Form.Control
              type="password"
              required
              onChange={(e) => setPassword(e.target.value)}
            />
          </Form.Group>
          <Button
            disabled={isFetching}
            className="w-100 mt-4 mb-4"
            type="submit"
          >
            Log In
          </Button>
        </Form>
        <div className="w-100 text-center mt-2">
          <Link to="/forgot-password">Forgot Password</Link>
        </div>
        <div className="w-100 text-center mt-3">
          Need an Account? <Link to="/signup">Sing Up</Link>
        </div>
      </Card.Body>
    </Card>
    )}
      
    </>
  );
}

问题分析与修复方案

核心问题

Login组件中,你通过useSelector获取的currentUser是整个auth状态对象(包含currentUser、isFetching、error三个属性),而不是对象内部的currentUser字段。由于对象本身永远是非空值,条件判断{currentUser ? <UpdateProfile/> : ...}永远为真,导致错误渲染UpdateProfile组件。

修复步骤

  1. 修正state选择逻辑
    将Login组件中获取currentUser的代码:

    const currentUser = useSelector((state) => state.auth);
    

    修改为:

    const currentUser = useSelector((state) => state.auth.currentUser);
    

    这样才能正确获取到初始为null的currentUser字段值。

  2. 修正handleSubmit逻辑
    原提交逻辑的判断逻辑写反了,应该是无用户时执行登录请求:

    async function handleSubmit(e) {
      e.preventDefault();
      try {
        if (!currentUser) {
          login(dispatch, { username, password });
          navigate('/');
        } else {
          navigate('/');
        }
      } catch (error) {
        console.log(error);
      }
    }
    
  3. 可选优化:合并useSelector调用
    可以把多个state选择合并为一次调用,减少重复操作:

    const { currentUser, isFetching, error } = useSelector((state) => state.auth);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 02:24:13