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

useSelector重渲染后无法获取Redux最新state值返回null如何解决?

问题描述

我正在开发用户页面,通过Redux的useSelector hook从状态中获取用户信息,代码如下:

import React, { useState, useEffect } from "react";
import profileImage from "../../resources/images/defaultProfile.png";
import { useSelector, useDispatch } from "react-redux";
import { userActions } from "../../state/actions";

const User = () => {
  const [isEditable, setIsEditable] = useState(false);

  const onChange = (e) => {
    setUser({
      ...user,
      [e.target.name]: [e.target.value],
    });
  };
  const onSubmit = () => {
    if (!isEditable) {
      setIsEditable(!isEditable);
    } else {
      //TODO update user data here
    }
  };
  const [user, setUser] = useState(useSelector((state) => state.user.user));

  return (
    user !== null && (
      <div className="container-fluid">
        <div className="row">
          <div className="col-md-9 border border-primary">user preference</div>
          <div className="col-md-3 border border-primary">
            <div className="row-cols-md-3 text-center">
              <img
                src={profileImage}
                alt="Profile image"
                style={{ width: "60%", height: "70%" }}
                className="border rounded-circle"
              />

              <form onSubmit={onSubmit} style={{ width: "100%" }}>
                <div className="mb-3">
                  <label htmlFor="userName" className="form-label">
                    User Name
                  </label>
                  <input
                    type="text"
                    name="name"
                    id="userName"
                    value={user.name}
                    onChange={onChange}
                    disabled={!isEditable ? "disabled" : ""}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userEmail" className="form-label">
                    User Email
                  </label>
                  <input
                    type="email"
                    name="email"
                    disabled={!isEditable ? "disabled" : ""}
                    id="userEmail"
                    value={user.email}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userPhone" className="form-label">
                    User Phone Number
                  </label>
                  <input
                    type="text"
                    disabled={!isEditable ? "disabled" : ""}
                    name="phoneno"
                    id="userPhone"
                    value={user.phoneno}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>

                <button type="submit">{isEditable ? "Update" : "Edit"}</button>
              </form>
            </div>
          </div>
        </div>
      </div>
    )
  );
};

export default User;

页面首次加载时数据正常,初始所有输入框均为禁用状态,点击编辑按钮后会修改isEditable状态启用所有输入框,提交按钮切换为「更新」,此时isEditable状态变更会触发页面重新渲染。我所有页面默认加载导航栏,导航栏中包含页面刷新时重新加载用户状态的逻辑,页面重新渲染时会重载全局用户状态,但不知为何useSelector无法获取最新值,仅返回null。
观察结论:尽管Redux中已经存在最新的状态值,完整重渲染完成后useSelector仍然无法拉取到最新的用户数据。请问应该采用什么方案解决该问题?


解决方案

根因说明

核心问题是将useSelector的返回值直接作为useState的初始值,useState的初始值仅在组件首次挂载时计算一次,后续Redux store中的user状态更新时,组件本地的user状态不会自动同步,就会出现Redux已经有最新值,但本地读取的还是旧值/初始null的情况。

修复代码

不需要把Redux的user存到本地冗余状态,直接读取useSelector的结果即可,编辑状态下的临时修改单独存本地状态,提交时再同步到Redux:

import React, { useState, useEffect } from "react";
import profileImage from "../../resources/images/defaultProfile.png";
import { useSelector, useDispatch } from "react-redux";
import { userActions } from "../../state/actions";

const User = () => {
  const [isEditable, setIsEditable] = useState(false);
  // 直接从Redux取最新用户数据,不要作为本地state的初始值
  const reduxUser = useSelector((state) => state.user.user);
  const dispatch = useDispatch();
  // 单独存储编辑状态下的临时用户数据
  const [editUser, setEditUser] = useState(null);

  // 进入编辑模式时同步最新的Redux用户数据到本地编辑状态
  useEffect(() => {
    if (isEditable && reduxUser) {
      setEditUser({...reduxUser});
    }
  }, [isEditable, reduxUser]);

  const onChange = (e) => {
    setEditUser({
      ...editUser,
      // 原代码多套了一层数组,已移除,避免值变成数组格式
      [e.target.name]: e.target.value,
    });
  };

  const onSubmit = (e) => {
    e.preventDefault();
    if (!isEditable) {
      setIsEditable(true);
    } else {
      // 提交时把编辑好的用户数据更新到Redux
      dispatch(userActions.updateUser(editUser));
      setIsEditable(false);
    }
  };

  // 渲染用的用户数据:编辑模式用本地临时数据,非编辑模式用Redux源数据
  const showUser = isEditable ? editUser : reduxUser;

  return (
    showUser !== null && (
      <div className="container-fluid">
        <div className="row">
          <div className="col-md-9 border border-primary">user preference</div>
          <div className="col-md-3 border border-primary">
            <div className="row-cols-md-3 text-center">
              <img
                src={profileImage}
                alt="Profile image"
                style={{ width: "60%", height: "70%" }}
                className="border rounded-circle"
              />

              <form onSubmit={onSubmit} style={{ width: "100%" }}>
                <div className="mb-3">
                  <label htmlFor="userName" className="form-label">
                    User Name
                  </label>
                  <input
                    type="text"
                    name="name"
                    id="userName"
                    value={showUser.name}
                    onChange={onChange}
                    // disabled直接传布尔值即可,无需字符串
                    disabled={!isEditable}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userEmail" className="form-label">
                    User Email
                  </label>
                  <input
                    type="email"
                    name="email"
                    disabled={!isEditable}
                    id="userEmail"
                    value={showUser.email}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userPhone" className="form-label">
                    User Phone Number
                  </label>
                  <input
                    type="text"
                    disabled={!isEditable}
                    name="phoneno"
                    id="userPhone"
                    value={showUser.phoneno}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>

                <button type="submit">{isEditable ? "Update" : "Edit"}</button>
              </form>
            </div>
          </div>
        </div>
      </div>
    )
  );
};

export default User;

额外修复的问题点

  • 原onChange方法中给字段赋值多套了一层数组,会导致输入的字符串变成数组格式,提交时出错,已移除冗余的数组包裹
  • disabled属性简化为直接传布尔值,无需额外拼接字符串
  • 拆分了Redux源数据和编辑临时数据,避免编辑过程中未提交的修改直接污染全局Redux状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 00:09:03