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

useNavigate路由跳转异常求助:点击按钮极少跳转到Dashboard

React Router useNavigate 跳转失败报错解决方案

问题描述

路由流程为 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 App

Consider 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:45:33