useNavigate路由跳转异常求助:点击按钮极少跳转到Dashboard
问题描述
路由流程为 login->countryselection->dashboard,在CountrySelection组件中点击跳转按钮(或用Link包裹)极少成功跳转,伴随报错出现。
报错信息
react-dom.development.js:18655 The above error occurred in the <Route.Provider> component:
at Routes (http://localhost:3000/static/js/bundle.js:109822:5) at Router (http://localhost:3000/static/js/bundle.js:109755:15) at BrowserRouter (http://localhost:3000/static/js/bundle.js:108564:5) at AppConsider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
logCapturedError @ react-dom.development.js:18655
update.callback @ react-dom.development.js:18688
callCallback @ react-dom.development.js:13980
commitUpdateQueue @ react-dom.development.js:14003
commitLayoutEffectOnFiber @ react-dom.development.js:23222
commitLayoutMountEffects_complete @ react-dom.development.js:24500
commitLayoutEffects_begin @ react-dom.development.js:24486
commitLayoutEffects @ react-dom.development.js:24424
commitRootImpl @ react-dom.development.js:26631
commitRoot @ react-dom.development.js:26499
performSyncWorkOnRoot @ react-dom.development.js:25931
flushSyncCallbacks @ react-dom.development.js:12103
(anonymous) @ react-dom.development.js:25468
react-dom.development.js:19012 Uncaught Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
at throwException (react-dom.development.js:19012)
at handleError (react-dom.development.js:26129)
at renderRootSync (react-dom.development.js:26259)
at recoverFromConcurrentError (react-dom.development.js:25664)
at performSyncWorkOnRoot (react-dom.development.js:25910)
at flushSyncCallbacks (react-dom.development.js:12103)
at react-dom.development.js:25468
组件代码
import { Typography } from 'antd' import './countryselection.scss' import { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { db } from '../../Utils/firebase-connection' import { getDoc, doc } from 'firebase/firestore'; const { Title } = Typography function CountrySelection() { const navigate = useNavigate() const changeCountry = () => { // localStorage.setItem('country', name) navigate('/dashboard') }; function UserButton(name) { return ( <div className='container padded' key={name}> <button onClick={ () => changeCountry() } className='button'>{ name }</button> </div> ) } const user3 = '' console.log('userinfo', user3); // const user = localStorage.getItem('user'); console.log('user', user3) const [countries, setCountries] = useState([]); function getCountries() { const docRef = doc(db, 'users', user3); getDoc(docRef) .then(response => { console.log(response); const tempCountries = response.data().countries.map(doc => ({ label: doc, })) console.log('countries', tempCountries) if (tempCountries.length === 1) { // navigate('/dashboard') } setCountries(tempCountries); // country = tempCountries; console.log('result', tempCountries); }) .catch(error => console.log(error.message)) } useEffect(() => { getCountries(); }, []) return ( <div className="country-wrapper"> <div className='country-form'> <div> <Title style={{ textAlign: 'center', margin: '1rem 0 1rem 0', color: 'white', }} level={3} > Select a Country </Title> </div> {countries.map((e) => UserButton(e.label))} </div> </div> ) } export default CountrySelection
解决方案
1. 用startTransition包裹跳转逻辑
报错核心提示是“同步输入响应时组件暂停,需用startTransition包裹更新操作”,说明跳转后加载的Dashboard组件存在Suspense相关异步操作(比如React.lazy懒加载、数据获取Suspense)。修改跳转函数:
import { startTransition } from 'react'; // ... const changeCountry = () => { // localStorage.setItem('country', name) startTransition(() => { navigate('/dashboard') }); };
2. 修复Dashboard组件的异步加载逻辑
如果Dashboard使用React.lazy懒加载,必须用Suspense包裹路由:
import { Suspense, lazy } from 'react'; import { Routes, Route } from 'react-router-dom'; const Dashboard = lazy(() => import('./Dashboard')); // 路由配置中 <Suspense fallback={<div>加载中...</div>}> <Route path="/dashboard" element={<Dashboard />} /> </Suspense>
3. 修复Firestore数据获取的潜在问题
当前代码中user3为空字符串,导致Firestore查询无效文档,调用response.data()会抛出错误。同时要判断文档是否存在:
// 正确获取用户ID,比如从localStorage读取 const user3 = localStorage.getItem('user') || ''; // 处理Firestore响应时增加判断 function getCountries() { if (!user3) { console.log('用户ID为空'); return; } const docRef = doc(db, 'users', user3); getDoc(docRef) .then(response => { if (!response.exists()) { console.log('用户文档不存在'); return; } const tempCountries = response.data().countries.map(doc => ({ label: doc, })) console.log('countries', tempCountries) if (tempCountries.length === 1) { startTransition(() => navigate('/dashboard')); } setCountries(tempCountries); }) .catch(error => console.log(error.message)) }
4. 优化组件结构(可选)
将嵌套的UserButton改为普通函数,避免不必要的组件嵌套:
const UserButton = (name) => ( <div className='container padded' key={name}> <button onClick={changeCountry} className='button'>{ name }</button> </div> )
内容的提问来源于stack exchange,提问作者Wenjie Liu

