ReactJS线上出现软导航检测错误,本地运行正常求排查
React路由线上部署导航异常问题排查
我开发了一个包含accounts.js和accountView.js的简单React应用,通过以下代码从accounts.js向accountView.js传递ID:
<td><FaPencilAlt/> <FaTrashAlt/><Link to={"/accounts"+"/"+x.id }><AiFillDiff/></Link></td>
本地localhost运行正常,但部署到线上服务器后无法正常工作,出现错误提示:检测到软导航:https://rwood.znapay.in/accounts/1。以下是我的Accounts.js和App.js代码:
Accounts.js
import React, { Component, useState, useEffect, useContext } from "react"; import { Card, Col, OverlayTrigger, Row, Tooltip, Table, } from "react-bootstrap"; import { AiFillDiff } from "react-icons/ai"; import "datatables.net-dt/js/dataTables.dataTables.js"; import { AES, enc } from "crypto-js"; import Popup from 'reactjs-popup'; import 'reactjs-popup/dist/index.css'; import "datatables.net-responsive-dt"; import "datatables.net-dt/css/jquery.dataTables.min.css"; import "react-data-table-component-extensions/dist/index.css"; import { Link, useNavigate } from "react-router-dom"; import { TokenContext } from "../AuthProvider"; import $ from "jquery"; import axios from "axios"; import { BsFillEnvelopeFill } from "react-icons/bs"; import { FaPencilAlt, FaTrashAlt, FaPlus } from "react-icons/fa"; import { decryptedAccessToken, encryptedAccessToken } from "../../Token"; import Header from '../Header' import Footer from '../Footer' const AccountsList = () => { const navigate = useNavigate(); const [formData, setFromdata] = useState({ account_record: "", }); const handleChange = (e) => { setFromdata({ ...formData, [e.target.name]: e.target.value }); }; const handleSubmit = (event) => { event.preventDefault(); const encryptedAccessToken = localStorage.getItem('access_token'); const secret_key = '4d3a23fba54bbef1e14dd44ba9591612'; if (encryptedAccessToken) { const decryptedAccessToken = AES.decrypt(encryptedAccessToken, secret_key).toString(enc.Utf8); fetch('https://rwood.znapay.in:5000/add/record', { method: "POST", body: JSON.stringify(formData), headers: { Authorization: `Bearer ${decryptedAccessToken}`, 'Content-Type': 'application/json' }, }) .then((response) => response.json()) .then((response) => { console.log(response) console.log(response.status) if (response.message === "record addedd successfully") { const account_record_new = response.account_type; navigate("/accounts/new-account", { state: { account_record: account_record_new }, }); } }) } }; const body=$(window).height() const header=$("#header").height() const nav=$(".navbar").height() const footer=$(".footer").height() const total_height=header+nav+footer; const window_height=body-total_height; console.log(total_height) console.log(body) $(".addAccount").css({"min-height":(window_height)+"px"}) const userRole = localStorage.getItem("role"); console.log(userRole); const { username ,token} = useContext(TokenContext); const [datas, setDatas] = useState([]); useEffect(() => { fetchData(); }, [decryptedAccessToken]); const fetchData = async () => { try { const response = await axios.get('https://rwood.znapay.in:5000/all/accounts', { headers: { Authorization: `Bearer ${decryptedAccessToken}` }, } ); const data = response.data; console.log(data) setDatas(data); $(document).ready(function(){ setTimeout(()=>{ $('#tables').DataTable(); },5) }) } catch (error) { console.error(error); } }; return ( <> <Header/> <div className="contactAccount"> <div className="page-header" id='add-account'> <div> <h2 className="main-content-title tx-24 mg-b-5">Accounts </h2> <ol className="breadcrumb"> <li className="breadcrumb-item active" aria-current="page">Dashboard / Accounts</li> </ol> </div> <div className="d-flex"> <div className="justify-content-center"> <Popup trigger={<button className="button add-accountrecord"> <FaPlus/> Add Account </button>} modal> <form onSubmit={handleSubmit} className="add-accounts"> <div className='form-group'> <label>Account Record Type</label><br/> <select name='account_record' className='form-control' onChange={handleChange} value={formData.account_record}> <option >--Select account record type--</option> <option value='Agent'>Agent</option> <option value='Bank'>Bank</option> <option value='Buyer'>Buyer</option> <option value='Supplier'>Supplier</option> <option value='Competitor'>Competitor</option> <option value='Employee'>Employee</option> <option value='Surveyor'>Surveyor</option> </select> </div> <input type='submit' className="btn btn-primary " value='Submit'/> </form> </Popup> </div> </div> </div> <div class='tasks'> <table id='tables'> <thead> <tr> <th>Account Name</th> <th>Account Alias</th> <th>Account Record Type</th> <th>Origin</th> <th>Phone</th> <th>Port</th> <th>Actions</th> </tr> </thead> <tbody> <React.Fragment> {datas.length > 0 ? ( datas.map((x) => ( <tr> <td>{x.account_name}</td> <td>{x.account_alias}</td> <td><span className='account-record'>{x.account_record_type}</span></td> <td>{x.origin}</td> <td>{x.phone}</td> <td>{x.port}</td> <td><FaPencilAlt/> <FaTrashAlt/><Link to={"/accounts"+"/"+x.id }><AiFillDiff/></Link></td> </tr> )) ) : ( <tr> <td colSpan="6">No data available</td> </tr> )} </React.Fragment> </tbody> </table> </div> </div> <Footer/> </> ); }; export default AccountsList;
App.js
import logo from './logo.svg'; import './App.css'; import 'bootstrap/dist/css/bootstrap.min.css' import Header from './components/Header' import Footer from './components/Footer' import OppShipmentList from './components/oppShipmentList' import Login from './components/Login' import Price from './components/price' import AddProduct from './components/addproduct' import Dashboard from './components/dashboard' import Contactus from './components/account/contacts' import Accountlist from './components/accountlist' import AllTcf from './components/alltcf' import AccountDetails from './components/accountDetails' import Addaccount from './components/account/addaccount' import Oppourtunity from './components/account/oppourtunity' import ResetPassword from './components/ResetPassword' import ResetConfirm from './components/ResetConfirm' import QuotesList from './components/quoteslist' import AddOppurtunity from './components/account/addoppurtunity' import AllQuotes from './components/account/allQuotes' import EditQuote from './components/account/editquote' import ProductMaster from './components/productMaster/productmaster' import Shipment from './components/account/shipment' import Quotes from './components/account/quotes' import AddTcf from './components/addTcf' import AddPricebook from './components/pricebook/addPricebook' import AddRecord from './components/accounts/addRecord' import NewAccount from './components/accounts/newAccount' import AccountsList from './components/accounts/accounts' import AccountViewPage from './components/accounts/accountViewPage' import AddContacts from './components/contact/addContacts'; import ContactLists from './components/contact/contactLists'; import PriceBooklist from './components/pricebook/priceBooklist' import AddRwoodusers from './components/rwoodusers/addRwoodusers' import UserList from './components/rwoodusers/userList' import AddRwoodCompany from './components/rwoodCompany/addRwoodcompany' import RwoodCompanyLists from './components/rwoodCompany/rwoodCompanyLists' import AddPrice from './components/price/addPrice' import UpdatePriceBook from './components/pricebook/updatePricebook' import PriceLists from './components/price/priceLists' import AddCotract from './components/contract/addCotract' import ContractList from './components/contract/contarctList' import AddOpportunitys from './components/opportunity/addOpportunitys' import AddRecords from './components/opportunity/addRecords' import AddQuotes from './components/opportunity/addQuotes' import OpportunityDetails from './components/opportunity/opportunityDetails' import OppourtunityList from './components/opportunity/oppourtunityList' import OpportunityShipmentDetail from './components/opportunity/opportunityShipmentDetail' import TcfList from './components/tcf/tcfList' import AddBank from './components/bank/addBank' import BankLists from './components/bank/BankLists' import AddoppShippment from './components/opportunity/addoppShippment' import ViewOpportunity from './components/opportunity/viewOpportunity' import OppShipmentLists from './components/opportunity/oppShipmentList' import ContractShippment from './components/shippment/contractShippment' import ContractShippmentList from './components/shippment/contractShippmentList' import NewProduct from './components/productMaster/addProductMaster' import ContactViewPage from './components/contact/contactViewPage' import { AES, enc } from "crypto-js"; import { BrowserRouter, Routes, Route, Navigate, useLocation, } from "react-router-dom"; import AuthProvider from "./components/AuthProvider"; import $ from 'jquery' function App() { const isAuthenticated = localStorage.getItem("access_token"); const location = useLocation(); console.log(isAuthenticated) return ( <AuthProvider> <Routes> <Route path="/" element={isAuthenticated ? <Dashboard /> : <Login />} isAuthenticated={isAuthenticated} /> <Route path="/login" isAuthenticated={isAuthenticated} element={ isAuthenticated ? ( <Navigate to={{ pathname: location.state?.from || "/", state: { from: location.pathname }, }} /> ) : ( <Login/> ) } /> <Route path="/accounts/:id" element={isAuthenticated ? <AccountViewPage/> : <Login />} isAuthenticated={isAuthenticated} /> <Route path="/accounts/accounts-list" element={isAuthenticated ? <AccountsList/> : <Login />} isAuthenticated={isAuthenticated} /> </Routes> </AuthProvider> ); } export default App;
问题排查与修复方案
缺失BrowserRouter包裹:React Router v6要求所有路由逻辑必须在
BrowserRouter组件内部运行。你的App.js导入了BrowserRouter但未使用,导致线上环境无法处理客户端路由,触发硬导航。修复时将Routes包裹在BrowserRouter中:function App() { const isAuthenticated = localStorage.getItem("access_token"); const location = useLocation(); return ( <AuthProvider> <BrowserRouter> <Routes> {/* 原有路由配置 */} </Routes> </BrowserRouter> </AuthProvider> ); }优化Link路径写法:原路径拼接
"/accounts"+"/"+x.id易出错,改用模板字符串更可靠:<Link to={`/accounts/${x.id}`}><AiFillDiff/></Link>服务器SPA路由配置:线上服务器需配置支持SPA路由,避免刷新子路由时返回404。以Nginx为例,添加如下配置:
location / { try_files $uri $uri/ /index.html; }useLocation使用限制:
useLocation钩子只能在BrowserRouter包裹的组件内使用,修复后可正常获取路由状态。
内容的提问来源于stack exchange,提问作者Simple Design
相关产品推荐
相关产品推荐

