Сбой инварианта: вы не должны использовать <Route> вне <Router>

Я использую react-router-dom для маршрутизации в своем React приложении. Часть моего приложения извлечена в другой пакет. Список зависимостей выглядит так:

./приложение/приборная панель/package.json

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

./приложение/компоненты/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'),
);

Если кто-то добавляет теги <Router> в попытке исправить это, обратите внимание, что вы должны импортировать BrowserRouter as Router, чтобы это работало.

qotsa42 07.12.2020 06:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
74
1
158 761
23
Перейти к ответу Данный вопрос помечен как решенный

Ответы 23

Вам также нужно импортировать именованный экспорт Router из react-router-dom и обернуть его вокруг компонентов коммутатора/маршрута.

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

Я оборачиваю все свое приложение в client.jsx

Pavel 06.04.2019 20:54

Это решение сработало и для меня, хотя я немного удивлен. Как и в OP, у меня есть это Router в моем клиентском коде.

Edward Chopuryan 23.10.2019 19:28

У вас есть висящая запятая в конце вызова рендеринга после document.getElementById('root').

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

Не проблема. JS это позволяет.

drublic 25.06.2019 15:13
Ответ принят как подходящий

Проблема с 2 экземплярами React

Попытка отобразить несколько экземпляров <BrowserRouter> вызвала это исключение в моем коде, спасибо за подсказку!

rodurico 07.10.2019 00:16

@rodurico У меня такая же проблема. Как вы это решили?

Sawan Patodia 30.06.2020 08:25

@SawanPatodia Мне пришлось перерисовать корневой компонент. У вас должен быть один <Router> внутри одного <BrowserRouter> во всем проекте.

rodurico 01.07.2020 15:22

Я решил эту загадочную ошибку, удалив зависимость «react-router-dom» из MyComponent. Я удалил «node_modules/react-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);

Если в папке компонента оставить 'react-router-dom', появится ошибка.

Проблема для меня заключалась в том, что я установил и react-router-dom, и react-router. Я удалил последний, и моя проблема была решена.

turnip 06.09.2019 15:48

Я получил это во время тестирования моего компонента, который связан с проектом (используя npm link) и из-за этого react-router-dom загружен более одного раза, в моем случае работает следующее решение:

Внутри webpack.config.js я добавил:

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

Если кто-то придет сюда с той же проблемой с <Link> вместо <Route>, как у меня, мне нужно было добавить как react-router, так и react-router-dom в качестве псевдонимов, чтобы это работало, даже если у меня нет react-router в качестве зависимости .

Phil Gibbins 23.07.2021 18:20

'Будьте здоровы!! Это также происходит при работе с локальными пакетами, которые имеют зависимость react-router-dom.

Jorge Kunrath 10.09.2021 18:07

У меня была аналогичная проблема с компонентом Redirect. Оказалось, что я вызывал Redirect из 'react-router', а не 'react-router-dom'.

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

В моем случае эта ошибка была вызвана смешением использования вещей (withRouter, MemoryRouter) из react-router и react-router-dom. Используя только вещи из react-router-dom, инвариантная ошибка исчезла. Надеюсь, это поможет кому-нибудь.

Вы должны включить тег Route, тег Link внутри тега 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";

просто добавь -дом.

У меня была такая же проблема с импортом Redirect из «реагирующего маршрутизатора».

jithu reddy 10.10.2020 07:07

Я решаю эту ошибку, заключая родительский компонент в 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}>
      <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>
)

После:

Индекс.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>
)

Я решил эту проблему, просто импортировав BrowserRouter из react-router-dom в index.js и добавив:

<BrowserRouter>
   <App>
 </BrowserRouter>

в пределах:

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

Использование тега <Link> в компоненте, который не имеет импорта, может привести к этой ошибке, попробуйте импортировать BrowserRouter из 'react-router-dom'

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

затем убедитесь, что ваши связанные теги заключены в тег

На самом деле проблема была в вашем корневом компоненте, где вы выполняете маршрутизацию, вы не должны добавлять какой-либо компонент за пределами тега Router в компонент, этот компонент ожидает только один или несколько компонентов, обернутых Route под Router в этих компонентах.

неправильный код (но он будет работать, но вы создаете ошибку) -

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>
  );
}

Мне удалось решить проблему, удалив <BrowserRouter> из router.js и включив его в 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 as Router, Route, Switch} из 'react-router-dom';

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

Я не уверен, что это хорошая практика, чтобы обернуть роутер таким образом.

mw509 22.07.2020 15:55

Я решил эту проблему, импортировав

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

и завернул все компоненты Route под компонент Router

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

У меня была похожая проблема при попытке заменить представления Rails в приложении Solidus.

Решение для меня состояло в том, чтобы отредактировать соперничество, чтобы использовать React Router, который я только что добавил, но, по-видимому, не полностью настроил.

Например, я отредактировал 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, Enzyme: Invariant Violation: You should not use or , To test a component (with Jest) that contains and withRouter you need to import Router in you test, not in your component import { BrowserRouter as Invariant Violation: You should not use or withRouter() outside a According to react router 4 docs, the components are considered valid, where I can create components composed of s, then import them into another component and place inside a .

Спасибо. Это как раз то, что мне нужно для тестирования.

Sarvar Khalimov 17.09.2021 21:59

Разве вы не должны использовать <MemoryRouter> для тестов?

StephenWeiss 24.09.2021 18:48

просто измените «реагировать-маршрутизатор» на «реагировать-маршрутизатор-дом»

import {Route} from "react-router";

к

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

Это сработало отлично!

Rohit Parte 25.10.2021 16:18

У меня была аналогичная ситуация с основным приложением, созданным с помощью CRA и библиотеки компонентов. У нас есть два экземпляра react-router-dom, работающих независимо. Компонент из библиотеки использует <Link>, а родительское приложение — <Router>.

Вдохновленный ответом @Pavel, я обнаружил, что проблему можно решить, добавив псевдонимы. Если вы используете webpack, вы можете изменить способ разрешения модуля react-router-dom. Вы можете перезаписать порядок по умолчанию, в котором веб-пакет будет искать ваши зависимости, и сделать node_modules вашего родительского приложения более приоритетным, чем порядок разрешения модулей узла компонента:

псевдонимы.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'),
};

которые используются config-override.js для переопределения настроек 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';

Самый простой ответ находится прямо в официальном документе от reactstrap для Navbar, см. этот сайт https://reactstrap.github.io/components/navbar/

Они руководствовались тем, что нам нужно использовать этот импорт

import {NavLink} from 'reactstrap';

Другие вопросы по теме