Програмно орієнтуватися за допомогою роутера реагування


1427

Завдяки цьому react-routerя можу використовувати цей Linkелемент для створення посилань, які в основному обробляються реактором.

Я бачу, як все це дзвонить this.context.transitionTo(...).

Я хочу зробити навігацію. Не за посиланням, а за допомогою випадаючого вибору (як приклад). Як я можу це зробити в коді? Що таке this.context?

Я бачив Navigationміксин, але чи можна це зробити без mixins?


26
@SergioTapia майте на увазі, що це питання стримує основний випуск реактивного маршрутизатора, головний випуск React та основний випуск javascript
Джордж Мауер

5
Ось посилання на підручник в офіційних документах маршрутизатора реагування v4: reacttraining.com/react-router/web/guides/scroll-restoration
chitzui

4
Ви можете перевірити цю відповідь stackoverflow.com/questions/44127739/…
Shubham Khatri

4
Я радий, що ти відповів на це, але мені сумно, що це має бути таким складним. Навігація в веб-додатку повинна бути легко і добре зафіксованою. VueJS робить це тривіальним. Кожен компонент отримує екземпляр маршрутизатора, який автоматично вводиться. У їх документах є чітко визначений розділ. router.vuejs.org/guide/essentials/navigation.html Мені подобається реагувати на багато речей, але іноді це так надмірно складно. </rant>
colefner

7
@GeorgeMauer Ви маєте рацію. Це не те, про що йдеться у цій громаді. Йдеться про відповіді на питання, а не сварки за рамки. Дякуємо за нагадування.
colefner

Відповіді:


1427

Маршрутизатор React v5.1.0 за допомогою гачків

У useHistoryмаршрутизаторі React> 5.1.0 з'явився новий гак, якщо ви використовуєте React> 16.8.0 та функціональні компоненти.

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

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

Реагує маршрутизатор v4

З v4 React Router є три підходи, які можна застосувати до програмної маршрутизації в межах компонентів.

  1. Використовуйте withRouterкомпонент вищого порядку.
  2. Використовуйте склад і візуалізуйте a <Route>
  3. Використовуйте context.

Маршрутизатор React - це переважно обгортка навколо historyбібліотеки. historyобробляє взаємодію з браузером window.historyдля вас із його веб-переглядачем та історією хешу. Він також пропонує історію пам'яті, яка корисна для середовищ, які не мають глобальної історії. Це особливо корисно при розробці мобільних додатків ( react-native) та тестуванні одиниць за допомогою Node.

historyПримірник має два методи для навігації: pushі replace. Якщо ви вважаєте historyмасив відвіданих місць, pushдодайте до масиву нове місце розташування та replaceзамінить поточне місце в масиві новим. Зазвичай ви хочете використовувати pushметод під час навігації.

У більш ранніх версіях Реагувати маршрутизатор, потрібно було створити свій власний historyпримірник, але в v4 <BrowserRouter>, <HashRouter>і <MemoryRouter>компоненти створюватиме браузер, хеш, і екземпляри пам'яті для вас. Маршрутизатор React забезпечує властивості та методи historyекземпляра, пов'язаного з вашим маршрутизатором, доступними через контекст під routerоб'єктом.

1. Використовуйте withRouterкомпонент вищого порядку

Компонент withRouterвищого порядку вводить historyоб'єкт як опору компонента. Це дозволяє отримувати доступ до методів pushі replaceметодів, не маючи справи з context.

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. Використовуйте склад і візуалізуйте a <Route>

<Route>Компонент не тільки для розташування відповідності. Ви можете візуалізувати бездоріжний маршрут, і він завжди буде відповідати поточному розташуванню . <Route>Компонент проходить той же реквізит , як withRouter, так що ви зможете отримати доступ до historyметодів через historyопору.

import { Route } from 'react-router-dom'

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. Використовуйте контекст *

Але ти, мабуть, не повинен

Останній варіант - той, який вам слід використовувати, лише якщо вам зручно працювати з контекстною моделлю React (API контексту React стабільний станом на v16).

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

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


24
Я намагався використовувати метод 1 таким чином withRouter (({{історія)) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Але це ніколи не працювало з маршрутизатором 4
Дмитро Малугін

57
ЩО!? Я можу просто використовувати withRouterзамість того, щоб пропускати historyчерез всі мої компоненти ?? Gahh, мені потрібно більше часу приділяти читанню документів ...
hellojeffhall

18
Як можна просто запустити, history.push('/new-location')не прив’язуючи цю поведінку до кнопки чи іншого елемента DOM?
Ніл

4
помилка кидка якUnexpected use of 'history' no-restricted-globals
Pardeep Jain

18
contextбільше не експериментальний, як реагує 16.
trysis

920

Відповідь React-Router 5.1.0+ (за допомогою гачків та React> 16.8)

Ви можете використовувати новий useHistoryгак на функціональних компонентах і програмно переходити:

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

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

Реагувати-маршрутизатор 4.0.0+ Відповідь

В версії 4.0 і вище використовуйте історію як опору свого компонента.

class Example extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

ПРИМІТКА: this.props.history не існує у випадку, якщо ваш компонент не був наданий <Route>. Ви повинні використовувати, <Route path="..." component={YourComponent}/>щоб мати this.props.history у своєму компоненті

Реагувати-маршрутизатор 3.0.0+ Відповідь

В версії 3.0 і вище використовуйте роутер як опору вашого компонента.

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

Реагувати-маршрутизатор 2.4.0+ Відповідь

У версії 2.4 і вище використовуйте компонент вищого порядку, щоб отримати маршрутизатор як опору вашого компонента.

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

Реагувати-маршрутизатор 2.0.0+ Відповідь

Ця версія назад сумісна з 1.x, тому немає необхідності в Посібнику з оновлення. Просто перегляд прикладів повинен бути досить хорошим.

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

import { browserHistory } from 'react-router'

Тепер у вас є доступ до історії вашого веб-переглядача, тому ви можете робити такі дії, як "push", "заміна" тощо ...

browserHistory.push('/some/path')

Подальше читання: Історії та навігація


Реагувати-маршрутизатор 1.xx Відповідь

Я не буду вникати в оновлення деталей. Про це можна прочитати в Посібнику з оновлення

Основна зміна питання тут - це зміна навігаційного міксину на історію. Тепер він використовує історію браузераAPI для зміни маршруту, тому ми будемо використовуватись pushState()відтепер.

Ось приклад використання Mixin:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

Зауважте, що це Historyпоходить від проекту rackt / history . Не від самого React-Router.

Якщо ви не хочете використовувати Mixin з якихось причин (можливо, через клас ES6), ви можете отримати доступ до історії, яку ви отримуєте від маршрутизатора this.props.history. Він буде доступний лише для компонентів, наданих маршрутизатором. Отже, якщо ви хочете використовувати його в будь-яких дочірніх компонентах, його потрібно передавати як атрибут via props.

Детальніше про нову версію ви можете прочитати в їх документації 1.0.x

Ось довідкова сторінка, зокрема про навігацію за межами вашого компонента

Він рекомендує захопити посилання history = createHistory()та зателефонувати replaceStateна це.

React-Router 0.13.x відповідь

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

Ось як я це зробив

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

Мені вдалося зателефонувати transitionTo()без необхідності доступу.context

Або ви можете спробувати фантазійний ES6 class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

React-Router-Redux

Примітка: якщо ви використовуєте Redux, є ще один проект під назвою ReactRouter-Redux , який дає вам Redux прив'язок для ReactRouter, використовуючи кілька той же підхід , що React-Redux робить

React-Router-Redux має декілька доступних методів, які дозволяють просту навігацію від творців всередині дій. Вони можуть бути особливо корисними для людей, які мають існуючу архітектуру в React Native, і вони хочуть використовувати ті самі шаблони в React Web з мінімальними накладними витратами.

Вивчіть наступні методи:

  • push(location)
  • replace(location)
  • go(number)
  • goBack()
  • goForward()

Ось приклад використання Redux-Thunk :

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>

3
Я використовую , v2.4.0але згаданий підхід не працює для мене, моє додаток не робить на все і консольні виходах: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functionось посилання на мій пост SO: stackoverflow.com/questions/37306166 / ...
nburk

7
Це має бути прийнята відповідь, прийнята - трохи безлад і дуже стара. @GiantElk У мене це працює, як описано у відповіді на версію 2.6.0.
JMac

2
Чи все ж такий підхід є рекомендованим способом для версії 3.0.x? Багато людей, здається, використовують contextспосіб.
велоп

6
в 4.0, цієї історії.props.історії не існує. Що відбувається?
Nicolas S.Xu

4
@ NicolasS.Xu this.props.historyне існує у випадку, якщо ваш компонент не був наданий <Route>. Ви повинні використовувати, <Route path="..." component={YourComponent}/>щоб мати this.props.historyв YourComponent.
vogdb

508

React-Router v2

Для останнього випуску ( v2.0.0-rc5), рекомендований спосіб навігації - безпосередньо натисканням на історію одинарного. Це ви можете бачити в Документі за межами компонентів, док .

Відповідний уривок:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

При використанні більш нових реагувати маршрутизатори API, ви повинні використовувати з historyз this.propsколи всередині компонентів так:

this.props.history.push('/some/path');

Він також пропонує, pushStateале це застаріло за попередженими попередженнями.

Якщо ви користуєтеся react-router-redux, він пропонує pushфункцію, яку ви можете відправляти так:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

Однак це може бути використане лише для зміни URL-адреси, а не для фактичного переходу на сторінку.


15
Не забувайте, що новіший API не використовує, import { browserHistory } from './react-router'а натомість створює історію, використовуючи import createBrowserHistory from 'history/lib/createBrowserHistory'. Пізніше ви можете отримати доступ historyіз реквізитів для компонентів:this.props.history('/some/path')
Ricardo Pedroni

7
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
Боббі

7
reakct-router-redux pushзмінює лише URL-адресу, фактично не змінює сторінку. Для обох, імпорт browserHistoryз react-routerі використання browserHistory.push('/my-cool-path'). На жаль, знайти це не дуже просто. github.com/reactjs/react-router/blob/master/docs/guides/…
Ендрю Самуельсен

4
Я використовую this.props.history.push ('/'), але змінюється лише URL-адреса ... Тут фактична маршрутизація не відбувається. Що я пропускаю?
rgcalsaverini


56

Ось як це можна зробити react-router v2.0.0з ES6 . react-routerвідійшов від міксинів.

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}

5
Я вважаю, що нинішня рекомендація - використовувати historyсинглтон, як заявляє @Bobby. Ви можете використовувати, context.routerале ви ускладнюєте тестування цих компонентів, оскільки екземпляри саме цього компонента не матимуть цього в контексті.
Джордж Мауер

2
@GeorgeMauer Я думаю, це залежить від того, де працює код. Згідно з документами про реакцію, рекомендується використання контексту.рутера, якщо він працює на сервері. github.com/reactjs/react-router/blob/master/upgrade-guides/…
KumarM

50

Відповідь React-Router 4.x:

Зрештою, мені подобається мати єдиний предмет історії, який я можу перенести навіть на зовнішні компоненти. Мені подобається робити один файл history.js, який я імпортую на вимогу, і просто маніпулювати ним.

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

Потрібно встановити історію , бібліотеку, якою користується react-router.

Приклад використання, позначення ES6:

history.js

import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()

BasicComponent.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

EDIT 16 квітня 2018 року:

Якщо вам доведеться перейти з компонента, який фактично відображений з Routeкомпонента, ви також можете отримати доступ до історії з реквізиту, наприклад:

BasicComponent.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}

2
За винятком того, що документи React Router говорять нам, що в більшості випадків не потрібно використовувати їх Routerзамість BrowserRouter. BrowserRouterстворює та підтримує historyдля вас об’єкт. Ви не повинні замовчуватись у створенні власного, лише якщо вам потрібна "глибока інтеграція з такими інструментами управління державою, як Redux".]] Reacttraining.com/react-router/web/api/Router
bobbyz

2
Це щось я навчився з часом і досвідом. Хоча, як правило, корисно використовувати за замовчуванням this.props.history, я ще не знайшов рішення, яке могло б допомогти мені зробити таке в класі, який не є компонентом чи іншим інструментом, який не побудований як компонент React, до якого ви можете передати реквізит. Дякую за відгук :)
Ерік Мартін

44

Для цього, хто не контролює сторону сервера, і через це використовується хеш-роутер v2:

Розмістіть свою історію в окремому файлі (наприклад, app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

І використовуйте його всюди!

Ваша точка входу для реактора-маршрутизатора (app.js ES6):

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

Ваша навігація всередині будь-якого компонента (ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})

1
Дякую. Можливо, мені чогось не вистачає. Чи це не точно так само, як два найкращих відповіді?
Джордж Мауер

2
Коли ви використовуєте "хеш" навігацію, в "react-router" v2 вам потрібно встановити додатковий модуль "історія" (якщо ви хочете уникати дивних хеш-запитів), а замість браузераHistory потрібно використовувати useRouterHistory (createHashHistory) ( {queryKey: false}). Це основна причина, чому я розмістив це. Я показав, як орієнтуватися в історії хешу.
Олексій Володько

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

4
чому ця відповідь не найкраща? Чому виникають проблеми з прототипами контексту чи HOC або подій, чому б просто не імпортувати історію та використовувати в будь-якому місці, де нам заманеться? просто намагаюся зрозуміти компроміс
storm_buster

@storm_buster немає компромісу. У нас є модулі ES6, і ми повинні їх використовувати! Це така типова вітрина використання вашого інструменту (реагуйте в даному випадку) на все, навіть на речі, для яких ви насправді не хочете їх використовувати.
Капай

40

Реагує маршрутизатор V4

тл: д-р;

if (navigate) {
  return <Redirect to="/" push={true} />
}

Проста і декларативна відповідь полягає в тому, що потрібно використовувати <Redirect to={URL} push={boolean} />в поєднанні зsetState()

push: boolean - коли це правда, перенаправлення натисне новий запис на історію замість заміни поточного.


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Повний приклад тут . Детальніше читайте тут .

PS. У прикладі використовуються ініціалізатори властивостей ES7 + для ініціалізації стану. Подивіться і тут , якщо вам цікаво.


Це найкраща відповідь, яку я знайшов. Використання withRouterне працювало, коли вже на маршруті, який перезавантажується. У нашому випадку нам довелося вибірково або робити setState(спричиняючи return <Redirect>), якщо вже на маршруті, чи history.push()з іншого місця.
karmakaze

Дуже, дуже розумно. І все ж дуже просто. Ткс. Я використовував його всередині ReactRouterTable, оскільки хотів обробити клацання по всій лінії. Використовується на onRowClick для встановлення стану. setState ({navigateTo: "/ path /" + row.uuid});
Ловато

це відповідь на кулі.
Нітін

31

Попередження: ця відповідь стосується лише версій ReactRouter до 1,0

Я оновлю цю відповідь після використання випадків використання 1.0.0-rc1!

Ви можете це зробити і без міксинів.

let Authentication = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  handleClick(e) {
    e.preventDefault();
    this.context.router.transitionTo('/');
  },
  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

Гетча з контекстами полягає в тому, що вона недоступна, якщо ви не визначите contextTypesкласу на класі.

Що стосується контексту, то це об'єкт, як реквізит, передається від батьків до дитини, але він передається неявно, без необхідності щоразу переосмислювати реквізит. Дивіться https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


26

Я спробував принаймні 10 способів зробити це, перш ніж щось працювало правильно!

Відповідь @Felipe Скіннера withRouterбула для мене трохи непосильною, і я не був впевнений, що хочу створити нові назви класів "ExportedWithRouter".

Ось найпростіший і найпростіший спосіб зробити це - навколо поточних React-Router 3.0.0 та ES6:

React-Router 3.xx з ES6:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

або, якщо це не ваш клас за замовчуванням, експортуйте так:

withRouter(Example);
export { Example };

Зауважте, що в 3.xx використовує <Link>сам компонент router.push, тож ви можете передавати йому все, що ви передали би <Link to=тегу, наприклад:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'

1
Це працює абсолютно чудово. Але відповідає 200 OKзамість 30xкоду. Як я можу виправити це питання?
Мухаммед Атеак Азам

1
Не впевнений. Це ніколи не підійшло для мене, оскільки це не зовнішній запит - це просто ваш браузер, який використовує власний код сторінки, щоб змінити те, що на цій сторінці. Ви завжди можете зробити вручну переадресацію JavaScript, якщо вам зручніше.
Бен Уілер

1
його також можна використовувати з @withRouter як декоратор класу ... чудово підходить mobx
Dan

21

Щоб зробити навігацію програмно, вам потрібно перенести нову історію до props.history у вашому component, щоб щось подібне може зробити роботу за вас:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;

Будь ласка, напишіть версію react-router
Ash

19

Для компонентів ES6 + React для мене працювало наступне рішення.

Я пішов за програмою Felippe Skinner, але додав рішення до кінця, щоб допомогти таким початківцям.

Нижче наведені версії, які я використав:

"react-router": "^ 2.7.0"

"реагувати": "^ 15.3.1"

Нижче - мій компонент реакції, де я використовував програмну навігацію за допомогою реактора-маршрутизатора:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

 loginComp.contextTypes = {
    router: React.PropTypes.object.isRequired
 }

 module.exports = loginComp;

Нижче наведено конфігурацію мого маршрутизатора:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));

19

Можливо, це не найкращий підхід, але ... Використовуючи реактор-маршрутизатор v4, наступний Typescript може дати ідею для деяких.

У наведеному нижче компоненті, наприклад LoginPage, routerоб'єкт доступний і просто зателефонуйте router.transitionTo('/homepage')для навігації.

Код навігації взято з .

"react-router": "^4.0.0-2", "react": "^15.3.1",

import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();

interface MatchWithPropsInterface {
  component: typeof React.Component,
  router: Router,
  history: History,
  exactly?: any,
  pattern: string
}

class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
  render() {
    return(
      <Match {...this.props} render={(matchProps) => (
             React.createElement(this.props.component, this.props)

        )}
       />
    )
  }
}

ReactDOM.render(
    <Router>
      {({ router }) => (
        <div>
          <MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
          <Miss component={NotFoundView} />
        </div>
      )}
    </Router>,

   document.getElementById('app')
);


1
Чому ви не використовуєте withRouter та BrowserHistory?
Ервін Майєр

1
@Erwin API відрізняється в v4. Дивіться це github.com/ReactTraining/react-router/isissue/3847 .
mcku

1
@mcku Звідки ти взяв файл типу DTS для друку для react-router v4?
jmathew

1
@jmathew У мене немає жодних визначень типів для
react

16

У React-Router v4 та ES6

Ви можете використовувати withRouterі this.props.history.push.

import {withRouter} from 'react-router-dom';

class Home extends Component {

    componentDidMount() {
        this.props.history.push('/redirect-to');
    }
}

export default withRouter(Home);

2
Вже згадувалося в декількох інших відповідях (в тому числі і в основній відповіді)
Джордж Мауер

13

Для використання withRouterз компонентом на основі класів спробуйте щось подібне нижче. Не забудьте змінити заяву про експорт, щоб використовувати withRouter:

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

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      <div>
        <Form onSubmit={ this.yourFunction } />
      </div>
    )
  }
}

export default withRouter(YourClass);

11

виходячи з попередньої відповіді
Жозе Антоніо Постіго і Бену Уілера,
новинка? має бути написано в Typescript
та використання декораторів
АБО статичного властивості / поля

import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";

export interface INavigatorProps {
    router?: ReactRouter.History.History;
}

/**
 * Note: goes great with mobx 
 * @inject("something") @withRouter @observer
 */
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

/**
 * Non decorated 
 */
export class Navigator2 extends Component<INavigatorProps, {}> {

    static contextTypes = {
        router: React.PropTypes.object.isRequired,
    };

    navigate: (to: string) => void;
    constructor(props: INavigatorProps, context: any) {
        super(props, context);
        let s = this;
        this.navigate = (to) =>
            s.context.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

з будь-яким встановленим сьогодні npm. "react-router": "^ 3.0.0" і
"@ types / react-router": "^ 2.0.41"


11

з React-Router v4 на горизонті, тепер існує новий спосіб зробити це.

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

react-lego - це приклад програми, який показує, як використовувати / оновлювати реактор-маршрутизатор, і він включає приклади функціональних тестів, які орієнтуються в додатку.


5
Це чудово підходить для навігації з функції візуалізації, хоча мені цікаво, як орієнтуватися на щось на зразок гачка життєвого циклу чи скорочення?
Рубен Мартинес-молодший

11

В реакції маршрутизатор v4. Я слідую за цим двома способами, щоб програмувати маршрут.

1. this.props.history.push("/something/something")
2. this.props.history.replace("/something/something")

Другий номер

Замінює поточний запис у стеку історії

Щоб отримати історію в реквізиті, можливо, доведеться обгортати ваш компонент

зРутер


Дякую!! Найкраща відповідь
Taha Farooqui

9

Якщо ви використовуєте хеш або історію браузера, тоді ви можете це зробити

hashHistory.push('/login');
browserHistory.push('/login');

2
hashHistory.push, надає Неможливо прочитати властивість "push" невизначеного. Звідки ви імпортуєте їх?
ArchNoob

import {hashHistory} з "react-router"; Ви можете імпортувати його таким чином вгорі.
Заман Афзал

Я використовую ваш зразок коду з мого файлу редуксної саги, імпортую так само, як ви сказали, і використовую його, але я продовжую отримувати цей TypeError.
ArchNoob

8

З поточною версією React (15.3) this.props.history.push('/location');працював для мене, але він показав таке попередження:

browser.js: 49 Попередження: [react-router] props.historyі context.historyзастаріли. Будь ласка, використовуйте context.router.

і я вирішив це context.routerтак:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;

1
Це працює для V4. Ну ... закрити ... це насправді має бути this.context.router.history.push ('/ back-location');
velohomme

7

Реактор-маршрутизатор V4

якщо ви використовуєте версію 4, ви можете використовувати мою бібліотеку (Безсоромний штекер), де ви просто відправляєте дію і все просто працює!

dispatch(navigateTo("/aboutUs"));

триплер


5

Тим, хто стикається з проблемами в його реалізації на реакторі-маршрутизаторі v4.

Ось робоче рішення для навігації через додаток для реагування із скороченими діями.

history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js / Route.jsx

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

файл з іншим файлом else_file.js АБО

import history from './history' 

history.push('/test') // this should change the url and re-render Test component

Все завдяки цьому коментарю: коментар з питань ReactTraining


4

Якщо трапляється спаровувати RR4 w / redux через reakct-router-redux , використовуйте також творці маршрутизаторів react-router-redux.

import { push, replace, ... } from 'react-router-redux'

class WrappedComponent extends React.Component {
  handleRedirect(url, replaceState = true) { 
    replaceState 
      ? this.props.dispatch(replace(url)) 
      : this.props.dispatch(push(url)) 
  }
  render() { ... }
}

export default connect(null)(WrappedComponent)

Якщо ви використовуєте функцію redux thunk / saga для управління потоком асинхронізації, імпортуйте вищевказані творці дій у режимах скорочення та підключіть для реакції компоненти за допомогою mapDispatchToProps, можливо, буде краще.


1
react-router-reduxзастаріли / архівуються в протягом тривалого часу
oligofren

4

Ви також можете використовувати useHistoryгачок у складі без стану. Приклад з док.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    <button type="button" onClick={() => history.push("/home")}>
      Go home
    </button>
  )
}

Примітка. Гачки були додані react-router@5.1.0і потребуютьreact@>=16.8


1
Хороший дзвінок, ви можете зауважити, до якої версії реагувати-маршрутизатора та реагувати, що стосується? Це нова зміна, яка не завжди була доступна
Джордж Мауер

3

Правильна відповідь була для мене під час написання

this.context.router.history.push('/');

Але вам потрібно додати PropTypes до свого компонента

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

Не забудьте імпортувати PropTypes

import PropTypes from 'prop-types';

Будь ласка, запишіть версію react-router, і що ви імпортували з react-router
Ash

Нічого не імпортувати, і це версія "react-router": "^ 4.2.0"
веб-майстер

3

Можливо, не найкраще рішення, але це виконує роботу:

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

// create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

В основному, логіка, пов'язана з однією дією (в даному випадку - видаленням), в кінцевому підсумку викликає тригер для переадресації. Це не ідеально, тому що ви додасте у свій розмітку вузол DOM "тригер" просто для того, щоб ви могли зручно викликати його при необхідності. Крім того, ви будете безпосередньо взаємодіяти з DOM, що в компоненті React може бути не бажаним.

Тим не менш, такий тип переадресації потрібен не так часто. Таким чином, одна чи дві додаткові, приховані посилання у вашій розмітці компонентів не зашкодять так сильно, особливо якщо ви дасте їм значущі імена.


Чи можете ви пояснити, чому ви коли-небудь використовувати це над прийнятим рішенням?
Джордж Мауер

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

2

Це працювало для мене, не потрібно спеціального імпорту:

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>

Звичайно, для цього потрібен спеціальний імпорт - ваш компонент не historyдодається propsлише сам по собі. Це походить від HoC, який вам потрібно буде імпортувати, щоб використовувати (компоненти, надіслані безпосередньо до Route, автоматично загортаються цим HoC, але тоді вам потрібно імпорт для Route...)
Джордж Мауер

2

використовуйте замість цього хаукертер, сучасну альтернативу реагувати на маршрутизатор

https://www.npmjs.com/package/hookrouter

import { useRoutes, usePath, A} from "hookrouter";

щоб відповісти на питання ОП про зв'язок через поле вибору, ви можете це зробити:

navigate('/about');

FYI. Сам автор називає цю бібліотеку «доказом концепції», і вона не мала активності майже рік (червень 2019 року).
ПАМ’ЯТЬ

@MEMark це тому, що це вже ідеально
StefanBob

Ну, 38 відкритих питань разом з тим, що версія 2.0 буде повною перезаписом згідно автору, говорить інакше.
ПАМ'ЯТКА

1

Для React Router v4 +

Якщо припустити, що вам не потрібно буде орієнтуватися під час початкового візуалізації (для цього ви можете скористатися <Redirect> компонент), це те, що ми робимо в нашому додатку.

Визначте порожній маршрут, який повертає нуль, це дозволить отримати доступ до об’єкта історії. Вам потрібно зробити це на верхньому рівні, де вашRouter визначено .

Тепер ви можете робити все те , що може бути зроблено по історії , як history.push(), history.replace(), і history.go(-1)т.д.!

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

let routeHistory = null;

export function navigateTo(path) {
  if(routeHistory !== null) {
    routeHistory.push(path);
  }
}

export default function App(props) {
  return (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}

1

react-router-dom: 5.1.2

  • Цей веб-сайт має 3 сторінки, всі вони відображаються динамічно у веб-переглядачі.

  • Хоча сторінка не оновлюється, зауважте, як маршрутизатор React постійно оновлює URL-адресу під час навігації по сайту. Це зберігає історію веб-переглядача, переконуючись, що такі речі, як кнопка "Назад" та закладки, працюють належним чином

  • Комутатор переглядає всі його дочірні елементи і робить перший , чий шлях збігається з поточним URL. Використовуйте будь-який час, коли у вас є кілька маршрутів, але ви хочете, щоб одночасно відображався лише один із них

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



export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

// You can think of these components as "pages"
// in your app.

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

function About() {
  return (
    <div>
      <h2>About</h2>
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
    </div>
  );
}```

Ласкаво просимо до SO! Коли ви відповідаєте на запитання з такою кількістю відповідей, постарайтеся показати ваші переваги.
Девід Гарсія Бодего

Це також не відповідає на питання, як це зробити програмно з імперативних js, а не з розміткою.
Джордж Мауер

1

Тож у моїй відповіді є 3 різні способи програмного перенаправлення на маршрут. Деякі рішення вже представлені, але наступні були зосереджені лише на функціональних компонентах із додатковим демо-додатком.

Використовуючи наступні версії:

реагувати: 16.13.1

реакція-дом: 16.13.1

реактор-маршрутизатор: 5.2.0

react-router-dom: 5.2.0

машинопис: 3.7.2

Конфігурація:

Отже, перш за все рішення використовується HashRouter, налаштоване так:

<HashRouter>
    // ... buttons for redirect

    <Switch>
      <Route exact path="/(|home)" children={Home} />
      <Route exact path="/usehistory" children={UseHistoryResult} />
      <Route exact path="/withrouter" children={WithRouterResult} />
      <Route exact path="/redirectpush" children={RedirectPushResult} />
      <Route children={Home} />
    </Switch>
</HashRouter>

З документації про <HashRouter>:

<Router>, Який використовує хеш частина URL (тобто window.location.hash) , щоб зберегти ваш призначений для користувача інтерфейс в синхронізації з URL.

Рішення:

  1. Використання <Redirect>для натискання useState:

Використовуючи функціональний компонент ( RedirectPushActionкомпонент з мого сховища), ми можемо використовувати useStateдля обробки переадресації. Хитра частина - це колись перенаправлення сталося, нам потрібно redirectповернути стан false. Використовуючи setTimeOutіз 0затримкою, ми чекаємо, поки React зобов'язується Redirectз DOM, а потім повернемо кнопку назад, щоб використати наступний раз.

Прошу знайти мій приклад нижче:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = <Redirect to="/redirectpush" push={true} />

        // in order wait until commiting to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    <button onClick={() => setRedirect(true)}>
        Redirect push
    </button>
</>

З <Redirect>документації:

Надання заходу <Redirect>перейде до нового місця. Нове місце розташування замінить поточне місце в стеці історії, як це робить переадресація на стороні сервера (HTTP 3xx).

  1. Використання useHistoryгачка:

У моєму рішенні є компонент, UseHistoryActionякий називається :

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

useHistoryКрюк дає нам доступ до об'єкта історії , який допомагає нам програмно або навігації по зміні маршрутів.

  1. Використовуючи withRouter, отримати historyз props:

Створений один компонент, який називається WithRouterAction, відображається як показано нижче:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

Читання з withRouterдокументації:

Ви можете отримати доступ до historyвластивостей об'єкта та найближчої <Route>відповідності через withRouterкомпонент вищого порядку. withRouterбуде передано оновлений match, locationта historyреквізит до загорнутого компонента кожного разу, коли він відображатиметься.

Демонстрація:

Для кращого представлення я створив сховище GitHub з цими прикладами, будь ласка, знайдіть його нижче:

https://github.com/norbitrial/react-router-programmatic-redirect-examples

Я сподіваюся, що це допомагає!

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