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;
问题根源
- 表单默认提交触发页面刷新:Login组件的form标签带有
action="/login",点击登录按钮会触发传统HTTP提交,导致页面刷新,React应用重启,上下文状态全部丢失。 - 上下文状态未持久化:即使无页面刷新,用户刷新页面或重新打开应用时,上下文存储的用户数据会因组件重新初始化重置为
null。 - 延迟跳转导致状态不同步: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
相关产品推荐
相关产品推荐

