Реагуйте на зміну URL-адреси маршрутизатора, але не перегляду


87

У мене проблеми зі зміною подання у відповідь на маршрутизацію. Я хочу лише показати список користувачів, і натискання кожного користувача має перейти на сторінку деталей. Ось маршрутизатор:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";

ReactDOM.render((
  <BrowserRouter>
    <div>
        <Route path="/" component={Users} />
        <Route path="/details" component={Details} />
    </div>
  </BrowserRouter>
), document.getElementById('app'))

Коли я використовую url / деталі, мій браузер переходить до цієї URL-адреси, але не змінює подання. Будь-який інший маршрут видає 404, тому він, здається, розпізнає маршрут, але не оновлюється.


Я отримую дві помилки: одна, яка стверджує, що використання проптипів з основного пакета реакцій застаріло. Дві заяви, що використовують React.createClass, не підтримуються. Я вважав, що це не пов'язано, оскільки код працює без використання маршрутизації.
MARyan87,

Чи правильно встановлений ваш компонент?
Джеремі Джон

Відповіді:


74

Вам потрібно вказати атрибут exactдля вашого indexRoute, інакше для парного /detailsмаршруту він все одно буде відповідати /. Також спробуйте імпортувати Routeзreact-router-dom

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from 'react-router-dom';
import Users from "./components/Users";

import Details from "./components/Details";

ReactDOM.render((
  <BrowserRouter>
    <div>
        <Route exact path="/" component={Users} />
        <Route path="/details" component={Details} />
    </div>
  </BrowserRouter>
), document.getElementById('app'))

ОНОВЛЕННЯ:

Інша справа, яку вам потрібно зробити, це приєднати ваш компонент Користувачі за допомогою withRouter. Вам потрібно використовувати withRouterлише тоді, коли ваш компонент не отримує Router props,

Це може трапитись у випадках, коли ваш компонент є вкладеним дочірнім елементом компонента, який відображається маршрутизатором, або ви не передали йому реквізити маршрутизатора, або коли компонент взагалі не пов'язаний з маршрутизатором і відображається як окремий компонент від Маршрути.

У Users.js add

import {withRouter} from 'react-router';

.........
export default withRouter(Users)

DOCS


попередження про прототипи можна видалити, встановивши npm install -S 'prop-types'та замінивши React.PropsTypes на PropTypes. Також оновіть package.json, щоб використовувати найновіші пакети, оскільки інші пакети все ще можуть використовувати React.PropTypes та React.createClass
Хатрі,

Також Чи намагаєтесь ви перезавантажити сторінку при зміні URL-адреси, щоб перевірити, чи завантажується
Шубхам Хатрі,

Я спробував перезавантажити сторінку, це не змінює подання. Він завантажується у перегляд Користувачів, навіть якщо URL-адреса / # / details
MARyan87,

1
Ви можете спробувати оновлений відповідь з Routeімпортовано з Реагуйте-маршрутизатор-dom` замістьreact-router
Shubham Khatri

Якщо його ще не вирішено, прив’яжіть свій компонент користувачів withRouter, це допомогло мені вирішити ту ж проблему раніше. Дай мені знати. Я також оновив код.
Шубхам Хатрі,

27

Вам просто потрібно обернути компоненти всередині за допомогою Router .

<Route exact path="/mypath" component={withRouter(MyComponent)} />

Ось зразок файлу App.js:

...
import { BrowserRouter as Router, Route, Switch, withRouter } from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";

class App extends Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/" component={withRouter(Home)} />
          <Route exact path="/profile" component={withRouter(Profile)} />
        </Switch>
      </Router>
    );
  }
}

export default App;

Додаткові

Якщо ви використовуєте реакційний маршрутизатор, компонентуWillReceiveProps буде викликано, коли URL-адреса змінюється.

componentWillReceiveProps(nextProps) {
    var currentProductId = nextProps.match.params.productId;
    var nextProductId = nextProps.match.params.productId; // from the new url
    ...
}

Примітка

Крім того, ви також можете обернути компонент у withRouter перед експортом, але тоді вам доведеться забезпечити кілька інших речей. Зазвичай я пропускаю цей крок.

export default withRouter(Profile)

3
<Маршрут точного шляху = "/ mypath" component = {withRouter (MyComponent)} /> у мене спрацював
Сантош Кумар,

15

У мене була та сама проблема, і я виявив, що це тому, що у мене вкладений маршрутизатор. Після того, як я видалив вкладений маршрутизатор і просто помістив мої маршрути, що стосуються конкретних компонентів, у компонент комутатора - проблема була вирішена без використання withRouter або внесення будь-яких додаткових змін.

<Router> // <--Remove nested Router
    <Switch>
      <Route exact path="/workflows" component={ViewWorkflows} />
      <Route path="/workflows/new" component={NewWorkflow} />
    </Switch>
</Router>

Юсуфбек описує подібне питання. Я думаю, що набагато чистіше зберігати маршрути, пов’язані з компонентами, на рівні вигляду, ніж зберігати всі їх в одному основному маршрутизаторі. У виробничому додатку це буде занадто багато маршрутів, щоб легко читати та налагоджувати проблеми.


14

Я зіткнувся з тією ж проблемою, але вирішив її. Домашню сторінку я розмістив як останню. Це працює для мене. Так само, як нижче.

    import React from "react";
    import ReactDOM from "react-dom";
    import { BrowserRouter } from 'react-router-dom';
    import Users from "./components/Users";
    import { Router, Route } from "react-router";
    import Details from "./components/Details";

    ReactDOM.render((
      <BrowserRouter>
        <div>
            <Route path="/details" component={Details} />
            <Route path="/" component={Users} />
        </div>
      </BrowserRouter>
    ), document.getElementById('app'))


5
Використання exactвласності також вирішило б це для вас.
isherwood

8

Під час використання Redux у мене були подібні проблеми, коли URL-адреса оновлювалася в адресному рядку, але програма не завантажувала відповідний компонент. Я зміг вирішити, додавши withRouter до експорту:

import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'

export default withRouter(connect(mapStateToProps)(MyComponentName))

7

У мене була подібна проблема, але з іншою структурою. Я додав один маршрутизатор, який буде обробляти всі маршрути, я використовував компонент Switch для перемикання видів. Але насправді цього не сталося. Змінено лише URL-адресу, але не перегляд. Причиною цього був компонент Link, який використовувався всередині компонента SideBar, який знаходився поза компонентом Router. (Так, я експортував SideBar з "withRouter", не працював). Отже, рішенням було перенести мій компонент SideBar, який містить усі компоненти Link, у мій маршрутизатор.

Проблема в моїх лінкерах, вони поза моїм маршрутизатором

<div className="_wrapper">
  <SideBar /> // Holds my all linkers
  <Router>
     <Switch>
       <Route path="/" component={Home} />
       <Route path="/users" component={Users} />
     </Switch>
  </Router>
 </div>

Рішення рухало мої лінкери до мого маршрутизатора

<div className="_wrapper">
  <Router>
     <SideBar /> // Holds my all linkers
     <Switch>
       <Route path="/" component={Home} />
       <Route path="/users" component={Users} />
     </Switch>
  </Router>
</div>

3
допомагаючи собі зробив мій день. Я пробував це з двома розділеними маршрутизаторами. Один знаходився у навігаційній панелі, а другий - у тілі, щоб вмістити компонент. Тепер я поміщаю все в один і той же маршрутизатор у батьківський компонент, і все працює як слід.
Маттеус Барбоза,

3
Відмінно - моє саме питання. Дякую
Джеффрі Борн

2
Дякую! Ти врятував мене !!
AzizStark

1
Я пробував все, включаючи withRouter, але тільки це рішення спрацювало ... трохи пояснення було б корисним, щоб зрозуміти, чому це відбувається
Джим

1
@Jim Я думаю , що реагувати-маршрутизатор використовує контекст API, і <Router />він же <BrowserRouter /> надає контекст для маршрутизації matchers як <Route />, <Switch /> і компоненти навігації , як <Link />, <Redirect />. Для того, щоб надати той самий контекст, вам слід обернути всі дочірні компоненти всередині постачальника контексту, який є <Router />.
Юсуфбек


5

BrowserRouter не зберігає історію у вашому випадку. Замість цього використовуйте "Маршрутизатор". Використання цього із власною історією як реквізитом може допомогти вирішити вашу проблему.

import {Router, Route, Switch, withRouter } from "react-router-dom";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import {createBrowserHistory} from 'history';

export const customHistory = createBrowserHistory();  //This maintains custom history

class App extends Component {
  render() {
    return (
      <Router history={customHistory}>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route exact path="/profile" component={Profile} />
        </Switch>
      </Router>
    );
  }
}

export default App;

Потім у своїх компонентах імпортуйте customHistory із програми та використовуйте її для навігації.

customHistory.push('/pathname');

Сподіваюся, ця допомога! :)


1
немає необхідності в exactатрибуті, коли ви використовуєтеSwitch
KBT

4

Вам потрібно додати точний шлях до індексу і замість того, щоб вкладати ці компоненти маршруту за допомогою div, використовуйте Switch from response-router-dom для перемикання між маршрутами.

import React from "react";
import ReactDOM from "react-dom";
import { Route, Switch } from 'react-router-dom';
import Users from "./components/Users";

import Details from "./components/Details";

ReactDOM.render((
  <div>
    <Switch>
        <Route path="/" component={Users} exact/>
        <Route path="/details" component={Details} />
    </Switch>
  </div>
), document.getElementById('app'))

3

У мене була подібна проблема з React Router версії 4:

Натискаючи <Link />компонент, URL-адреса змінюватиметься, а подання - ні.

Одне з переглядів використовувало, PureComponentа не Component(імпортувало зreact ), і це було причиною.

Замінивши всі відображені маршрутом компоненти, які використовували PureComponentдо Component, моя проблема була вирішена.

(Джерело дозволу: https://github.com/ReactTraining/react-router/issues/4975#issuecomment-355393785 )


1
Дякую. Це мені це виправило. Але якраз той компонент, що містив Switch, мені довелося перейти з Component замість PureComponent, щоб зміна подання в реальному часі працювала.
Крістіан Вестербек

1
Я змінив свій чистий компонент на компонент, проте він не працює для мене.
Косалрам Рама Крішнан

2

Я стикався з подібною проблемою, яку вирішив сподобатися, будь ласка, подивіться, сподіваюся, вона працює.

Вам потрібно використовувати функцію componentWillReceiveProps у вашому компоненті.

натиснув посилання вперше, зателефонувавши за адресою www.example.com/content1/ componentDidMount ().

Тепер, коли ви натискаєте інше посилання, скажіть, що www.example.com/content2/ викликається той самий компонент, але цього разу проп змінюється, і ви можете отримати доступ до цього нового реквізиту за допомогою componentWillReceiveProps (nextProps), який ви можете використовувати для виклику API Або зробити стан пустим і отримати новий даних.

componentWillReceiveProps(nextProps){
     //call your API and update state with new props
}

1

Хм, немає жодного ПЕРЕКЛЮЧАТЕЛЯ, який би насправді міняв види.

ось як я використовую маршрутизатор для переключення зі сторінки landin на головний сайт

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


//App.jsx
render()
{
    return <div>
        <Switch>
            <Route exact path='/' component={Lander}/>
            <Route path='/vadatajs' component={Vadatajs}/>
        </Switch>
    </div>
}

https://jsfiddle.net/Martins_Abilevs/4jko7arp/11/

ups я виявив, що ви використовуєте інший маршрутизатор .. жаль, то, можливо, ця скрипка буде для вас корисною

https://fiddle.jshell.net/terda12/mana88Lm/

можливо ключ рішення прихований у черзі для основної функції візуалізації ..

Router.run(routes, function(Handler) {
    React.render(<Handler />, document.getElementById('container'));
});

1

Я отримую той самий випуск. Я не думаю, що в цьому випадку йому потрібно додати проп за допомогою Router, просто перевірте у своєму NavLink, що ви пишете правильну назву шляху як деталі. для маршруту спробуйте почати з конкретного маршруту до загального, наприклад

<Route path="/details" component={Details} />
<Route path="/" component={Users} />

у вашому NavLink це має бути приблизно так

 <NavLink className="nav-link" to="/details">
   details<span className="sr-only">(current)</span>
 </NavLink>

зауваження для імпорту - краще розпочати, імпортуючи всі речі, пов’язані з React, після цього імпортуйте інший модуль, такий як цей:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from 'react-router-dom';
import Users from "./components/Users";
import { Router, Route } from "react-router";
import Details from "./components/Details";

приходьте так:

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

import Users from "./components/Users";    
import Details from "./components/Details";

1

Для мене я мав:

export MyClass extends React.Component

з:

export default withRouter(MyClass)

Тим часом у своєму App.js я мав:

import { MyClass } from './MyClass'

Ті, хто грає в домашню гру, можуть побачити мою проблему. Я не отримував імпорту з маршрутизатором, переданим у дочірні класи. Щоб очистити це, я перемістив виклик withRouter в оголошення компонента Route:

<Router exact path={'/myclass'} component={withRouter(MyClass)} />

Ще в MyClass я змінив його на експорт за замовчуванням:

export default MyClass extends React.Component

А потім, нарешті, в App.js я змінив імпорт на:

import MyClass from './MyClass'

Сподіваємось, це комусь допомагає. Це гарантує, що у мене не було двох способів експортувати один і той самий клас, тим самим обходячи preRuter prepend .


0

Спробуйте це,

import React from "react";

import ReactDOM from "react-dom";
import Users from "./components/Users";
import { Router, Route } from "react-router";


import Details from "./components/Details";

ReactDOM.render((
  <Router>
        <Route path="/" component={Wrapper} >
            <IndexRoute component={Users} />
            <Route path="/details" component={Details} />
        </Route>
  </Router>
), document.getElementById('app'))

Визначте компонент Wrapper, який буде відображати this.props.children. Це буде прокладено належним чином.
Вайбхав Сінгх

0

Ви повинні перевірити це: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md

Тому це, безумовно , НЕ Usersабо Details, тому що вони безпосередньо надають <Route>, і locationбудуть отримувати переданіprops .

Мені цікаво, навіщо вам <div>між <BrowserRouter>та між <Route>? Видаліть це і дайте мені знати, якщо це працює.


0

У мене була подібна проблема з умовним макетом:

class LayoutSwitcher extends Component {
  render () {
    const isLoggedIn = this.props.isLoggedIn
    return (
      <React.Fragment>
        { isLoggedIn
          ? <MainLayout {...this.props} />
          : <Login />
        }
      </React.Fragment>
    )
  }
}

і переписав умови так:

  render () {
    const isLoggedIn = this.props.isLoggedIn
    if (isLoggedIn) {
      return <MainLayout {...this.props} />
    }
    return <Login />
  }

Це вирішило це. У моєму випадку здається, що контекст було втрачено.



0

У мене була та сама проблема, і я виправив це, імпортуючи історію з папки @types у node_modules. Я імпортував його з npm (npm i @history)


0

У мене теж була та сама проблема. Хоча це не дуже ефективне рішення, я вирішив його хитрим методом. Метод ComponentDidMount працює кожного разу, коли змінюється наша URL-адреса. У рамках методу ми можемо порівняти попередню URL-адресу з поточною, а також змінити стан або оновити сторінку.

componentDidUpdate(prevProps) {
    if (this.props.match.url !== prevProps.match.url) {
        //this.props.history.go(0) refresh Page
        //this.setState(...) or change state
    }
}

-1

Я теж зустрів неприємності.

https://github.com/chengjianhua/templated-operating-system

І я спробував рішення, згадані Шубамом Хатрі, але це не працює.


Я вирішив цю проблему, можливо, можу вам допомогти.

https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md

Згідно з наведеним вище керівництвом, коли ви використовуєте PureComponentабо використовуєте інструменти управління станом, такі як redux, mobx... Це може заблокувати оновлення вашого маршруту. Перевірте компонент маршруту, переконайтесь, що ви не заблокували рендеринг компонента.


-2

спробуйте додати prop forceRefresh = {true} до BrowserRouter (Router)

import {BrowserRouter as Router} from "react-router-dom";

<Router forceRefresh={true}>
/// your <switch> and <route>
</Router>

це працює для мене.

до речі це не реальне рішення: D

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.