使用react-router-dom v6路由组件时出现createHref读取未定义错误求助
问题:React Router v6 路由跳转报错
Uncaught TypeError: Cannot read properties of undefined (reading 'createHref') 尝试使用react-router-dom v6实现组件路由跳转时触发该错误,当前项目使用styled-components,不确定是否与此问题相关。路由定义在App.js中,负责跳转的按钮组件在SideBySideButtons.js中,核心代码如下:
App.js
import React from 'react'; import { Routes, Route, Router } from 'react-router-dom'; import Landing from './components/Landing'; import EarlyAccess from './components/LandingPages/EarlyAccess'; import WebFont from 'webfontloader'; if (process.env.NODE_ENV === 'development') { WebFont.load({ google: { families: ['Barlow', 'Playfair Display', 'Overpass'] } }); } /* Rather than create a memory history object inside app.js, we create it in bootstrap.js because we want to customize it quite a bit */ export default ({ history }) => { return ( <div> <Router location={history.location} history={history}> <Routes> <Route exact path="/earlyaccess" element={ <EarlyAccess /> } /> <Route exact path="/learn" element={ <EarlyAccess /> } /> <Route path="/" element={ <Landing /> } /> </Routes> </Router> </div> ); };
SideBySideButtons.js
import React from 'react'; import { Link as RouterLink } from 'react-router-dom'; import styled from 'styled-components'; const DisplayBlock = styled.div` display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: center; border-radius: 3px; -webkit-transition: all 350ms ease; transition: all 350ms ease; color: #000; font-size: 16px; text-transform: uppercase; @media screen and (max-width: 767px) { padding-top: 10px; } ` const EarlyAccessLink = styled(RouterLink).attrs({ to: '/earlyaccess'})` display: inline-block; padding: 9px 15px; margin-top: 20px; border: 0; border-radius: 3px; font-family: 'Playfair Display', sans-serif; font-size: 16px; font-weight: 400; line-height: inherit; text-transform: uppercase; text-decoration: none; cursor: pointer; background-color: #0c0a89; color: #fff; -webkit-transition: all 350ms ease; transition: all 350ms ease; &:hover { background-color: #09d5b0; -webkit-transform: translate(0px, -2px); -ms-transform: translate(0px, -2px); transform: translate(0px, -2px); text-decoration: none; } @media screen and (max-width: 991px) { padding-right: 15px; padding-left: 15px; } ` const LearnMoreLink = styled(RouterLink).attrs({ to: '/learn'})` cursor: pointer; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; margin-top: 20px; margin-left: 15px; padding: 9px 15px; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; border-style: solid; border-width: 1px; border-color: #15113b; border-radius: 3px; -webkit-transition: all 350ms ease; transition: all 350ms ease; background-color: transparent; color: #0c0a89; font-family: 'Playfair Display', sans-serif; font-size: 16px; font-weight: 400; line-height: inherit; text-decoration: none; text-transform: uppercase; @media screen and (max-width: 991px) { padding-right: 15px; padding-left: 15px; } &:hover { background-color: #15113b; border-color: #ffd343; color: #fff; box-shadow: 1px 1px 12px 0 rgba(0, 0, 0, 0.08); text-decoration: none; -webkit-transform: translate(0px, -2px); -ms-transform: translate(0px, -2px); transform: translate(0px, -2px); text-decoration: none; } ` export default function Buttons() { return ( <React.Fragment> <DisplayBlock> <EarlyAccessLink>Early Access</EarlyAccessLink> <LearnMoreLink>Learn More</LearnMoreLink> </DisplayBlock> </React.Fragment> ) }
解决方案
该错误与styled-components无关,核心原因是react-router-dom v6中<Router>组件的API发生了变化:
- v6的
<Router>不再接受history属性,而是需要navigator属性 - 自定义history对象的传递方式不符合v6要求,导致路由上下文无法正确初始化,
<Link>组件找不到createHref等路由方法
修复方案1:使用内置<BrowserRouter>(推荐)
如果不需要自定义history逻辑,直接替换为v6内置的<BrowserRouter>即可,它会自动处理history:
import React from 'react'; // 替换Router为BrowserRouter import { Routes, Route, BrowserRouter } from 'react-router-dom'; import Landing from './components/Landing'; import EarlyAccess from './components/LandingPages/EarlyAccess'; import WebFont from 'webfontloader'; if (process.env.NODE_ENV === 'development') { WebFont.load({ google: { families: ['Barlow', 'Playfair Display', 'Overpass'] } }); } export default () => { return ( <div> <BrowserRouter> <Routes> {/* v6中Route默认精确匹配,无需exact属性 */} <Route path="/earlyaccess" element={ <EarlyAccess /> } /> <Route path="/learn" element={ <EarlyAccess /> } /> <Route path="/" element={ <Landing /> } /> </Routes> </BrowserRouter> </div> ); };
注意:v6的<Route>组件不再支持exact属性,默认采用精确匹配规则。
修复方案2:自定义history(仅当需要时使用)
如果必须使用自定义history(比如内存history用于测试),需要使用history库创建history对象,并传递给<Router>的navigator属性:
import React from 'react'; import { Routes, Route, Router } from 'react-router-dom'; // 导入history库创建自定义history import { createBrowserHistory } from 'history'; import Landing from './components/Landing'; import EarlyAccess from './components/LandingPages/EarlyAccess'; import WebFont from 'webfontloader'; const history = createBrowserHistory(); if (process.env.NODE_ENV === 'development') { WebFont.load({ google: { families: ['Barlow', 'Playfair Display', 'Overpass'] } }); } export default () => { return ( <div> {/* v6中传递navigator而非history */} <Router location={history.location} navigator={history}> <Routes> <Route path="/earlyaccess" element={ <EarlyAccess /> } /> <Route path="/learn" element={ <EarlyAccess /> } /> <Route path="/" element={ <Landing /> } /> </Routes> </Router> </div> ); };
验证
你的SideBySideButtons.js中对RouterLink的styled-components封装是正确的,只要路由上下文正常传递,就能正常触发跳转,无需修改该文件代码。
内容的提问来源于stack exchange,提问作者melv3223
相关产品推荐
相关产品推荐

