Next.js保持URL整洁时路由刷新后查询参数丢失的解决方法
解决Next.js跳转后刷新丢失username参数的问题
你当前的问题根源在于:使用router.push时,第二个参数(用户看到的URL路径)没有包含username查询参数,首次跳转时Next.js的客户端路由会在内存里暂存这个参数,但刷新页面后,浏览器从服务器重新请求页面,此时URL里没有username,router.query自然解析不到这个值。因为router.query的所有参数都是从当前URL的查询字符串里提取的,URL里没存的内容刷新后必然丢失。
要实现URL整洁+刷新不丢失username的需求,不能依赖router.query传递敏感/不想暴露的参数,以下是两种可行方案:
方案一:全局状态管理(Context API)
通过React Context把username存在全局状态中,跳转前后直接读写全局状态,无需通过URL传递。
1. 创建用户上下文
// src/contexts/UserContext.tsx import { createContext, useContext, useState, ReactNode } from 'react'; type UserContextType = { username: string | null; setUsername: (name: string | null) => void; }; const UserContext = createContext<UserContextType | undefined>(undefined); export const UserProvider = ({ children }: { children: ReactNode }) => { // 初始化时从localStorage读取,解决刷新后状态丢失问题 const [username, setUsername] = useState<string | null>(() => { if (typeof window !== 'undefined') { return localStorage.getItem('username'); } return null; }); const updateUsername = (name: string | null) => { if (typeof window !== 'undefined') { name ? localStorage.setItem('username', name) : localStorage.removeItem('username'); } setUsername(name); }; return ( <UserContext.Provider value={{ username, setUsername: updateUsername }}> {children} </UserContext.Provider> ); }; export const useUser = () => { const context = useContext(UserContext); if (!context) throw new Error('useUser必须在UserProvider内部使用'); return context; };
2. 在_app.tsx中全局包裹Provider
// src/pages/_app.tsx import { UserProvider } from '../contexts/UserContext'; import type { AppProps } from 'next/app'; export default function App({ Component, pageProps }: AppProps) { return ( <UserProvider> <Component {...pageProps} /> </UserProvider> ); }
3. JoinRoom.tsx中设置用户名并跳转
import { useRouter } from 'next/router'; import { useState } from 'react'; import { useUser } from '../contexts/UserContext'; const JoinRoom = () => { const router = useRouter(); const { setUsername } = useUser(); const [roomId, setRoomId] = useState(''); const [username, setLocalUsername] = useState(''); const handleSubmit = () => { setUsername(username); // 存到全局状态 router.push(`/editor/${roomId}`); // URL无需带任何额外参数 }; return ( <div> <input value={roomId} onChange={(e) => setRoomId(e.target.value)} placeholder="房间ID" /> <input value={username} onChange={(e) => setLocalUsername(e.target.value)} placeholder="用户名" /> <button onClick={handleSubmit}>加入房间</button> </div> ); }; export default JoinRoom;
4. [roomid].tsx中读取用户名
import { useRouter } from 'next/router'; import { useUser } from '../contexts/UserContext'; const RoomPage = () => { const router = useRouter(); const { roomid } = router.query; const { username } = useUser(); return ( <div> <p>当前房间ID:{roomid}</p> <p>当前用户名:{username || '未获取到'}</p> </div> ); }; export default RoomPage;
方案二:Cookie存储
把username存在浏览器Cookie中,刷新后可以直接从Cookie读取,支持服务器端渲染场景。
1. 安装依赖
npm install js-cookie @types/js-cookie
2. JoinRoom.tsx中设置Cookie并跳转
import { useRouter } from 'next/router'; import { useState } from 'react'; import Cookies from 'js-cookie'; const JoinRoom = () => { const router = useRouter(); const [roomId, setRoomId] = useState(''); const [username, setLocalUsername] = useState(''); const handleSubmit = () => { // 存储Cookie,有效期1天,可根据需求调整 Cookies.set('username', username, { expires: 1, path: '/' }); router.push(`/editor/${roomId}`); }; return ( <div> <input value={roomId} onChange={(e) => setRoomId(e.target.value)} placeholder="房间ID" /> <input value={username} onChange={(e) => setLocalUsername(e.target.value)} placeholder="用户名" /> <button onClick={handleSubmit}>加入房间</button> </div> ); }; export default JoinRoom;
3. [roomid].tsx中读取Cookie
如果是客户端渲染:
import { useRouter } from 'next/router'; import { useState, useEffect } from 'react'; import Cookies from 'js-cookie'; const RoomPage = () => { const router = useRouter(); const { roomid } = router.query; const [username, setUsername] = useState(''); useEffect(() => { const storedName = Cookies.get('username'); if (storedName) setUsername(storedName); }, []); return ( <div> <p>当前房间ID:{roomid}</p> <p>当前用户名:{username || '未获取到'}</p> </div> ); }; export default RoomPage;
如果需要服务器端渲染(比如页面是SSR),可以通过getServerSideProps读取Cookie:
import { useRouter } from 'next/router'; const RoomPage = ({ username }: { username: string }) => { const router = useRouter(); const { roomid } = router.query; return ( <div> <p>当前房间ID:{roomid}</p> <p>当前用户名:{username || '未获取到'}</p> </div> ); }; export async function getServerSideProps(context) { // 从请求头的Cookie中读取 const username = context.req.cookies.username || ''; return { props: { username } }; } export default RoomPage;
内容的提问来源于stack exchange,提问作者sohdata
相关产品推荐
相关产品推荐

