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

React中useUserContext无法将登录数据传递至Profile页面问题

React上下文数据无法从Login传递到Profile的问题修复

问题描述

我的React应用中,useUserContext存储的用户数据无法从Login页面正常传递到Profile页面。已确认Login页面中数据成功存入上下文,但Profile页面中user始终显示为null。

代码示例

useUserContext.js

import { createContext, useState, useContext } from 'react';

const UserContext = createContext();

export function useUserContext() {
  return useContext(UserContext);
}

export function UserContextProvider({ children }) {
  const [user, setUser] = useState(null);

  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
}

App.js

import React from 'react';
import { Route, Routes } from 'react-router-dom';
import "./styles/signup.css";
import "./styles/login.css";
import "./styles/profile.css";
import Navbar from './components/Navbar';
import Signup from './components/Signup';
import Login from "./components/Login";
import Homepage from './components/Homepage';
import Notifications from './components/Notifications';
import Profile from './components/Profile';
import Interpage from './components/Interpage';
import Yourvideos from './components/Yourvideos';
import Tagline from './components/Tagline';
import Trending from './components/Trending';
import { UserContextProvider } from "./components/Usercontext";
import CreateVideo from './components/Createvideo';

function App() {
  const isCreateVideo = window.location.pathname.startsWith('/createvideo');

  return (
    <div>
      <UserContextProvider>
        {!isCreateVideo && <Navbar />}
        {!isCreateVideo && <Interpage />}
        <Routes>
          <Route exact path="/" element={<Signup />} />
          <Route exact path="/login" element={<Login />} />
          <Route exact path="/home" element={<Homepage />} />
          <Route exact path="/notifications" element={<Notifications />} />
          <Route exact path="/profile" element={<Profile />} />
          <Route exact path="/yourvideos" element={<Yourvideos />} />
          <Route exact path="/tagline" element={<Tagline />} />
          <Route exact path="/trending" element={<Trending />} />
          <Route exact path="/createvideo" element={<CreateVideo />} />
        </Routes>
      </UserContextProvider>
    </div>
  );
}

export default App;

Profile.jsx

import React from 'react';
import userImage from '../images/Profile.jpg';
import { useUserContext } from './Usercontext';

const Profile = () => {
  const { user } = useUserContext();

  return (
    <div className="page-container">
      <div className="profile-page-container">
        <div className="profile-row">
          <div className="profile-box user-image-box">
            <img src={userImage} alt="User" className="user-image round-user-image" />
          </div>
          <div className="profile-box name-box">
            <i className="fa-solid fa-user"></i>
            <span className="element-label">Name:</span>
            <span className="element-value">{user && user[0]}</span>
          </div>
        </div>
        <div className="profile-row">
          <div className="profile-box email-box">
            <i className="fa-solid fa-envelope"></i>
            <span className="element-label">Email:</span>
            <span className="element-value">{user && user[1]}</span>
          </div>
          <div className="profile-box phone-box">
            <i className="fa-solid fa-phone"></i>
            <span className="element-label">Phone:</span>
            <span className="element-value">{user && user[2]}</span>
          </div>
        </div>
        <div className="profile-row">
          <div className="profile-box dob-box">
            <i className="fa-solid fa-calendar"></i>
            <span className="element-label">Date of Birth:</span>
            <span className="element-value">{user && user[3]}</span>
          </div>
          <div className="profile-box dob-box">
            <i className="fa-solid fa-location-pin"></i>
            <span className="element-label">Location:</span>
            <span className="element-value">{user && user[4]}</span>
          </div>
        </div>
        <div className="user-bio">
          <h2>Bio</h2>
          <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
          </p>
        </div>
      </div>
    </div>
  );
};

export default Profile;

Login.jsx

import React from 'react';
import { useState } from 'react';
import { useUserContext } from './Usercontext';
import { useNavigate } from 'react-router-dom';
import { getDocs, collection, query, where } from 'firebase/firestore';
import { db } from './firebaseconfig';

const Login = () => {
  const Navigate = useNavigate();
  const [data, setData] = useState({
    email: '',
    password: ''
  });
  const { setUser } = useUserContext();

  const handleInput = (event) => {
    let newInput = { [event.target.name]: event.target.value };
    setData({ ...data, ...newInput });
  };

  const handleLogin = async (event) => {
    event.preventDefault();

    const { email, password } = data;

    const usersRef = collection(db, 'users');
    const q = query(usersRef, where('email', '==', email));
    const querySnapshot = await getDocs(q);

    if (querySnapshot.empty) {
      alert('Login failed: User not found');
      return;
    }

    const userDoc = querySnapshot.docs[0];
    const userData = userDoc.data();
    const userArray = [userData.name, userData.email, userData.phoneNumber, userData.dob, userData.country];

    if (userData.password === password && userData.email === email) {
      setTimeout(() => {
        setUser(userArray);
        Navigate('/home');
      }, 1000);
    } else {
      alert('Login failed: Incorrect password');
    }
  };

  return (
    <div className='login_page'>
      <div className='login_box'>
        <form className='login_input_box' action='/login'>
          <h2 className='login_top_topic'>Login</h2>

          <div className='login-wrapper-input'>
            <i id='i_tags' className='fa-solid fa-envelope'></i>
            <input
              type='email'
              name='email'
              onChange={handleInput}
              placeholder='Email'
              autoComplete='off'
              value={data.email}
            />
          </div>

          <div className='login-wrapper-input'>
            <i id='i_tags' className='fa-solid fa-lock'></i>
            <input
              type='password'
              name='password'
              onChange={handleInput}
              placeholder='Password'
              autoComplete='off'
              value={data.password}
            />
          </div>

          <button className='login_button' onClick={handleLogin}>
            Login
          </button>
        </form>
        <p className='Not_have_Account'>
          Not Have Account <a className='Not_have_Account_p' href='/'>
            Create a Account
          </a>
        </p>
      </div>
    </div>
  );
};

export default Login;

问题根源

  1. 表单默认提交触发页面刷新:Login组件的form标签带有action="/login",点击登录按钮会触发传统HTTP提交,导致页面刷新,React应用重启,上下文状态全部丢失。
  2. 上下文状态未持久化:即使无页面刷新,用户刷新页面或重新打开应用时,上下文存储的用户数据会因组件重新初始化重置为null。
  3. 延迟跳转导致状态不同步:Login中用setTimeout延迟设置状态并跳转,可能造成状态更新与路由跳转不同步。

修复方案

1. 修复Login组件的表单提交行为

移除form标签的action属性,避免页面刷新;同时去掉不必要的延迟跳转:

// Login.jsx
<form className='login_input_box'>
  {/* 其余内容不变 */}
</form>

// 修改handleLogin逻辑
if (userData.password === password && userData.email === email) {
  setUser(userArray);
  localStorage.setItem('user', JSON.stringify(userArray));
  Navigate('/home');
}

2. 持久化上下文状态到localStorage

修改useUserContext.js,初始化时从localStorage读取数据,状态变化时同步存储:

// useUserContext.js
import { createContext, useState, useContext, useEffect } from 'react';

const UserContext = createContext();

export function useUserContext() {
  return useContext(UserContext);
}

export function UserContextProvider({ children }) {
  const [user, setUser] = useState(() => {
    const savedUser = localStorage.getItem('user');
    return savedUser ? JSON.parse(savedUser) : null;
  });

  useEffect(() => {
    if (user) {
      localStorage.setItem('user', JSON.stringify(user));
    } else {
      localStorage.removeItem('user');
    }
  }, [user]);

  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
}

3. 优化App.js的路由判断逻辑

使用React Router的useLocation钩子替代直接访问window.location,避免不必要的组件重渲染:

// App.js
import { Route, Routes, useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();
  const isCreateVideo = location.pathname.startsWith('/createvideo');

  // 其余内容不变
}

4. 可选:优化用户数据结构(提升可读性)

将用户数据从数组改为对象:

// Login.jsx中修改userArray为对象
const userObj = {
  name: userData.name,
  email: userData.email,
  phone: userData.phoneNumber,
  dob: userData.dob,
  location: userData.country
};
setUser(userObj);
localStorage.setItem('user', JSON.stringify(userObj));

// Profile.jsx中修改展示逻辑
<span className="element-value">{user?.name}</span>
<span className="element-value">{user?.email}</span>
<!-- 其余字段同理 -->

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:44:51