不变式失败: 您不应该在 < 路由器 > 之外使用 < Route >

我在 React应用程序中使用 react-router-dom进行路由。我的应用程序的一部分被提取到另一个包中。依赖项列表如下:

./app/dashboard/package.json

{
"dependencies": {
"@app/components": "^1.0.0",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react-router-dom": "^5.0.0"
}
}

./app/Component/package.json

{
"peerDependencies": {
"react-router-dom": "^5.0.0"
}
}

当我使用来自 @app/components的需要来自 react-router-dom的组件时,我得到这个错误:

Uncaught Error: Invariant failed: You should not use <Route> outside a <Router>
The above error occurred in the <Context.Consumer> component:
Uncaught (in promise) Error: Invariant failed: You should not use <Route> outside a <Router>

为什么抛出这个错误? 在 App.js中我使用 BrowserRouter

import React, { Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';
import { Placeholder } from '@app/components';


const Auth = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Auth'));
const Index = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Index'));


const App = () => (
<Suspense fallback={<Placeholder />}>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" component={Index} />
</Switch>
</Suspense>
);


export default App;

客户 jsx

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';


import App from './App';


render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
182530 次浏览

您还需要从 react-router-dom导入命名的导出 Router,并将其包装在 Switch/Route 组件中。

const App = () => (
<Router>
<Suspense fallback={<Placeholder />}>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" component={Index} />
</Switch>
</Suspense>
</Router>
);

document.getElementById('root')之后的渲染调用结束处有一个挂起的逗号。

render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);

2个 React 实例的故障

我从 MyComponent 中删除了对“ response-router-dom”的依赖,从“ package.json”中删除了“ node _ module/response-router-dom”和“ package.json”,从而解决了这个神秘的错误 我的应用程序结构如下:

    AppFolder
├── README.md
├── build
├── node_modules
│   ├── react-router-dom
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── index.js
├── redux
│   ├── reducers.js
│   └── store.js
└── serviceWorker.js




MyComponent
├── README.md
├── dist
├── node_modules
│   ├── react-router-dom
├── package-lock.json
├── package.json
├── rollup.config.js
└── src
├── index.js
├── styles.css
└── test.js

这是 App.js 的源代码

import MyComponent from 'MyComponent'


export default App(){
return (
<div className="App">
<HashRouter>
<div>
<header className="App-header">


</header>
<Route path="/home" component={MyComponent}/>
</div>
</HashRouter>
</div>)
}

这是 MyComponent 的导出

export default withRouter(MyComponent);

如果“ response-router-dom”保留在组件文件夹中,则会出现错误。

我得到了这个在测试我的组件链接到项目(使用 npm link) ,因为该 react-router-dom加载不止一次,以下解决方案在我的情况下工作:

webpack.config.js内部,我补充道:

resolve: {
alias: {
'react-router-dom': path.resolve('./node_modules/react-router-dom')
}
}

我在使用重定向组件时也遇到了类似的问题,结果是我用“反应路由器”而不是“反应路由器”来调用重定向。

Error: Invariant failed: You should not use <Redirect> outside a <Router>

在我的例子中,这个错误是由于混淆了从 response-router 和 response-router-dom 中使用的东西(with Router,Memory Router)而造成的。通过只使用反应路由器域中的内容,不变误差消失了。希望这对大家有帮助。

你应该包括路由标签,链接标签内的路由器标签。

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";


const Home = () => {
return (
<div>
<p>Home</p>
</div>
);
};


const About = () => {
return (
<div>
<p>About</p>
</div>
);
};


const Contact = () => {
return (
<div>
<p>Contact</p>
</div>
);
};
class App extends Component {
render() {
return (
<Router>
<div>
<h1>W3Adda - Simple SPA</h1>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Users</Link>
</li>
</ul>
</nav>


<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</div>
</Router>
);
}
}


export default App;

我通过改变来解决这个问题:

import {Route, Switch} from "react-router";

import {Route, Switch} from "react-router-dom";

随便说说。

我通过将父组件包装在路由器中来解决这个错误。

在解决错误之前

<Header />
<div className="col-md-12 pd-0-0">
<div className="row">
<Sidebar />
<div className="col-sm-10 col-md-10 pd-0-0" style={style}>
<Router>
<Switch>
<Route path="/dashboard/check-in" component={CheckIn} />
<Route path="/dashboard/deals" component={Deals} />
<Route path="/dashboard/events" component={Events} />
<Route path="/dashboard/invoice" component={Invoice} />
<Route path="/dashboard/notification" component={Notification} />
<Route path="/dashboard/profile" component={Profile} />
<Route path="/dashboard/redemption" component={Redemptions} />
<Route path="/dashboard/restriction-management" component={RestrictionManagement} />
</Switch>
</Router>
</div>
</div>
</div>

在解决错误之后

<Router>
<Header />
<div className="col-md-12 pd-0-0">
<div className="row">
<Sidebar />
<div className="col-sm-10 col-md-10 pd-0-0" style={style}>
<Switch>
<Route path="/dashboard/check-in" component={CheckIn} />
<Route path="/dashboard/deals" component={Deals} />
<Route path="/dashboard/events" component={Events} />
<Route path="/dashboard/invoice" component={Invoice} />
<Route path="/dashboard/notification" component={Notification} />
<Route path="/dashboard/profile" component={Profile} />
<Route path="/dashboard/redemption" component={Redemptions} />
<Route path="/dashboard/restriction-management" component={RestrictionManagement} />
</Switch>
</div>
</div>
</div>
</Router>

在运行测试时,我的 Create React 应用程序也有同样的问题,我通过将 <Router></Router放在 App.js而不是像往常一样放在 Index.js中来解决这个问题。

以前:

Index.js

ReactDOM.render(
<React.StrictMode>
<GlobalStyle />
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);

App.js

return (
<div className="App">
<Header />
<Route path="/blabla" component={Whatever}
</div>
)

之后:

Index.js:

ReactDOM.render(
<React.StrictMode>
<GlobalStyle />
<App />
</React.StrictMode>,
document.getElementById('root')
);

App.js:

return (
<div className="App">
<Router>
<Header />
<Route path="/blabla" component={Whatever}
</Router>
</div>
)

我只是从 react-router-dom导入 index.js中的 BrowserRouter就解决了这个问题,并补充道:

<BrowserRouter>
<App>
</BrowserRouter>

内:

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'));

在没有导入的组件中使用 <Link>标记可能会导致此错误,请尝试从 'react-router-dom'导入 BrowserRouter

import {BrowserRouter , Link} from 'react-router-dom';

然后确保在标签中包装你的链接标签

实际上,问题出在您正在进行路由的根组件中,您不应该在组件中添加 Router标记之外的任何组件,该组件只需要 Route在该组件中的 Router下包装单个/多个组件。

错误的代码(但是它会运行,但是你正在创建 bug)-

function App() {
return (
<div className="App">
<Header/>
<Router>
<Switch>
<Route path="/" exact>
<Home />
</Route>
</Switch>
</Router>
</div>
);
}

我只删除 <Header/>,它解决了问题。

编写代码-

function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/" exact>
<Home />
</Route>
</Switch>
</Router>
</div>
);
}

我设法通过从 router.js中移除 <BrowserRouter>并将其包含在 app.js中来解决这个问题

export default function  Routes() {
return (
     

<Switch>
<Route path="/" exact component={Home} />
<Route path="/book" component={Book} />
<Route path="/client" component={Client} />
<Route path="/rent" component={Rent} />
<Route path="/dash" component={Dash} />
</Switch>
    

);
}
function App() {
return (
<div>
  

<BrowserRouter>
<Header></Header>
    

<Routes/>
</BrowserRouter>
</div>
);
}

在组件之外使用 路由器。将所有组件包装在 路由器中,然后就可以在组件中使用 林克

从“反应路由器域”导入{ BrowserRouter 作为路由器,路由器,交换机} ;

<Router>
<Appbar />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/mac" exact component={Mac} />
</Switch>
<Footer />
</Router>

我已经通过进口解决了这个问题

import {BrowserRouter as Router, Route} from 'react-router-dom';

并将所有 Route组件包装在 Router组件下

 <Router>
<Route exact path='/' component={HomePage} />
</Router>

在 Solidus 应用程序中尝试替换 Rails 视图时,我也遇到过类似的问题。

对我来说,解决方案是编辑比赛使用反应路由器,我刚刚添加,但显然没有完全配置。

例如,我编辑了 views/spree/home/index.html:

<%= javascript_pack_tag 'application' %>
<%= react_component("Home/Index") %>

致:

<%= javascript_pack_tag 'application' %>
<%= react_component("Routes") %>

为了更多的参考,这里是我的 javascript/components/Route.js:

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from "./Home/Index";
import Product from "./Products/Show";


class Routes extends React.Component {
render() {
return (
<Router>
<Route exact path="/" component={Home} />
<Route path="/products/:slug" component={Product} />
</Router>
);
};
};


export default Routes;

我在测试时遇到了这个问题,并通过用路由器包装我的测试组件来解决它。

import React from 'react';
import ReactDom from 'react-dom';
import Header from '../components/Header/Header';
import { BrowserRouter } from 'react-router-dom';


it('renders Header without crashing', () => {
const div = document.createElement('div');


ReactDom.render(
<BrowserRouter>
<Header />
</BrowserRouter>,
div);


ReactDom.unmountComponentAtNode(div);
});

玩笑,酶: 不变违反: 你不应该使用或,到 测试一个包含和使用路由器的组件(使用 Jest) 需要在测试中导入路由器,而不是在组件导入中导入{ 浏览器路由器作为不变违反: 您不应该使用或 根据反应路由器4文档, 组件被认为是有效的,在这里我可以创建组件 组成,然后将它们导入到另一个组件中 在一个。

只要把“反应路由器”改成“反应路由器”

import {Route} from "react-router";

import {Route} from "react-router-dom";

我用 CRA 和组件库创建的主应用程序也有类似的情况。我们有两个独立工作的 react-router-dom实例。库中的组件使用 <Link>,而父应用程序使用 <Router>

受@Pavel 回答的启发,我发现问题可以通过添加别名来解决。如果您正在使用 webpack,您可以更改它解析 react-router-dom模块的方式。您可以覆盖 webpack 查找依赖项的默认顺序,并使您的父应用程序 node _ module 比组件节点模块解析顺序具有更高的优先级:

化名 js

const fs = require('fs');
const path = require('path');


const directory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(directory, relativePath);


module.exports = {
react: resolveApp('node_modules/react'),
'react-router-dom': resolveApp('node_modules/react-router-dom'),
};

用来覆盖默认的 CRA 设置:

const { addWebpackAlias, override, removeModuleScopePlugin } = require('customize-cra');
const aliases = require('./aliases');


module.exports = override(removeModuleScopePlugin(), addWebpackAlias(aliases));

或者对于 webpack.config.js (如果不是 CRA) :

resolve: {
alias: {
"react-router-dom": path.resolve(appFolder, "node_modules", "react-router-dom"),
}
}

如果您正在使用 GatsbyJS 并得到此错误,只需更改您的

import { Link } from "react-router-dom";

import { Link } from 'gatsby';

最简单的答案就是来自 Navbar reactstrap 的官方文档,见这个网站

他们指导我们需要使用这种进口

import {NavLink} from 'reactstrap';

我在用路由器包装 App 组件时遇到了同样的问题

错误:

import React, { Suspense } from 'react';
import { BrowserRouter, Switch, Route, withRouter } from 'react-router-dom';
import { Placeholder } from '@app/components';


const Auth = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Auth'));
const Index = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Index'));


const App = () => (
<BrowserRouter>
<Suspense fallback={<Placeholder />}>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" component={Index} />
</Switch>
</Suspense>
</BrowserRouter>
);


export default withRouter(App);

解决方案:

我们已经使用了 Switch 组件,在此之后我已经删除了路由器

    import React, { Suspense } from 'react';
import {BrowserRouter, Switch, Route } from 'react-router-dom';
import { Placeholder } from '@app/components';
    

const Auth = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Auth'));
const Index = React.lazy(() => import(/* webpackPrefetch: true */ './pages/Index'));
    

const App = () => (
<BrowserRouter>
<Suspense fallback={<Placeholder />}>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" component={Index} />
</Switch>
</Suspense>
</BrowserRouter>
);
    

export default App;

对于那些在进行单元测试时遇到这个问题的人来说,我已经解决了这个问题:

function mountComponentWithRouter(Component, props) {
const Teste = withRouter(prop => <Component {...prop} {...props} />);


return mount(
<HashRouter>
<Teste />
</HashRouter>,
{
context: { router },
childContextTypes: { router: PropTypes.object.isRequired }
}
);
}

通过这种方式,Component中的任何反应路由器组件都将拥有在运行应用程序时通常自然传递下来的所有道具(路径名、哈希、状态、搜索)。