Программная навигация с помощью маршрутизатора react

С react-router можно использовать Link элемент для создания ссылок, которые изначально обрабатываются маршрутизатором react.

Я вижу внутренне он называет this.context.transitionTo(...).

Я хочу сделать навигацию, но не по ссылке, например, из выпадающего списка. Как я могу сделать это в коде? Что такое this.context?

Я видел Navigation mixin, но могу ли я сделать это без mixins?

25 ответов


реагировать маршрутизатор v4

С v4 маршрутизатора React существует три подхода, которые можно использовать для программной маршрутизации внутри компонентов.

  1. использовать withRouter выше-того компонента.
  2. используйте композицию и визуализируйте <Route>
  3. использовать context.

React Router-это в основном обертка вокруг history библиотека. history управляет взаимодействием с помощью браузера window.history для вас с его браузером и хэш-историями. Он также предоставляет историю памяти, которая полезна для сред, которые не имеют глобальной истории. Это особенно полезно при разработке мобильных приложений (react-native) и модульное тестирование с узлом.

A history экземпляр имеет два метода навигации:push и replace. Если вы думаете о history как массив посещенных местах, push добавит новое местоположение в массив и replace заменит текущее местоположение в массиве с новым. Как правило, вы захотите использовать push метод при навигации.

в более ранних версиях React Router вам пришлось создать свой собственный history экземпляр, но в v4 <BrowserRouter>, <HashRouter> и <MemoryRouter> компоненты будут созданы экземпляры браузера, хэша и памяти для вас. React Router делает свойства и методы history экземпляр, связанный с вашим маршрутизатором, доступен через контекст, под


React-Router 4.0.0+ ответ

в 4.0 и выше, использовать историю в качестве опоры компонента.

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

React-Маршрутизатор 3.0.0+ ответ

в 3.0 и выше используйте маршрутизатор в качестве опоры вашего компонента.

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

React-Маршрутизатор 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
};

React-Маршрутизатор 2.0.0+ ответ

эта версия совместима с 1.х поэтому нет необходимости в руководстве по обновлению. Достаточно просто привести примеры.

тем не менее, если вы хотите переключиться на новый шаблон, внутри маршрутизатора есть модуль browserHistory, к которому вы можете получить доступ с

import { browserHistory } from 'react-router'

теперь у вас есть доступ к истории браузера, поэтому вы можете делать такие вещи, как push, replace и т. д... Например:

browserHistory.push('/some/path')

Читать далее: история и навигация


React-Маршрутизатор 1.х.х ответ

я не буду вдаваться в детали модернизации. Вы можете прочитать об этом в обновить Руководство

основным изменением в вопросе здесь является изменение от навигационного миксина к истории. Теперь он использует браузер historyAPI для изменения маршрута, поэтому мы будем использовать pushState() отныне.

вот пример использования Mixin:

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

обратите внимание, что это History происходит от rackt/история. Не от самого React-маршрутизатора.

если вы не хотите использовать Mixin по какой-то причине (возможно, из-за класса ES6), затем вы можете получить доступ к истории, которую вы получаете от маршрутизатора от this.props.history. Он будет доступен только для компонентов, отображаемых вашим маршрутизатором. Итак, если вы хотите использовать его в любых дочерних компонентах, он должен быть передан как атрибут через props.

вы можете прочитать больше о новом выпуске на их 1.0.х документация

здесь страница справки конкретно о навигации за пределами вашего компонента

это рекомендует захватить ссылку history = createHistory(), а вызов replaceState об этом.

React-Маршрутизатор 0.13.x ответ

я попал в ту же проблему и мог найти решение только с помощью навигационного миксина, который поставляется с react-router.

вот как я это сделал

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, есть еще один проект под названием React-Router-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>

React-Router v2

для последнего выпуска (v2.0.0-rc5), рекомендуемый метод навигации-это прямое нажатие на синглтон истории. Вы можете видеть это в действии в навигация вне компонентов doc.

соответствующий отрывок:

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

если вы используете более новый API react-router, вам нужно использовать 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-адреса, а не для фактического перехода на страницу.


вот как вы это делаете с react-router v2.0.0 С ЕС6. react-router отошел от mixins.

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
}

для этого, кто не контролирует серверную сторону и из-за этого использует хэш-маршрутизатор v2:

разместить история в отдельный файл (например, app_history.Яш на ES6):

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

export default appHistory;

и использовать его везде!

ваша точка входа для react-router (app.Яш на 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()
  }
})

React-Маршрутизатор 4.х ответ :

С моей стороны, мне нравится иметь один объект истории, который я могу носить даже внешние компоненты. Что мне нравится, так это иметь единую историю.JS файл, который я импортирую по требованию, и просто манипулировать им.

вы просто должны изменить BrowserRouter к маршрутизатору и укажите историю prop. Это ничего не меняет для вас, кроме того, что у вас есть свой собственный объект истории, которым вы можете манипулировать хотеть.

вам нужно установить история библиотека используется react-router.

пример использования, ES6 обозначения:

история.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>;
    }
}

редактировать 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>;
    }
}

предупреждение: этот ответ охватывает только версии ReactRouter до 1.0

я обновлю этот ответ с помощью 1.0.0-rc1 вариантов использования после!

вы можете сделать это без mixins тоже.

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

gotcha с контекстами заключается в том, что он недоступен, если вы не определяете contextTypes на классе.

что касается того, что такое контекст, это объект, такой как реквизит, который передается от родителя к ребенку, но он передается вниз неявно, без необходимости каждый раз заново объявлять реквизит. Смотри https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


Я пытался по крайней мере 10 способов сделать это, прежде чем что-то работало!

@Фелипе Скиннера withRouter ответ был немного подавляющим для меня, и я не был уверен, что хочу сделать новые имена классов "ExportedWithRouter".

вот самый простой и чистый способ сделать это, около текущего React-Router 3.0.0 и ES6:

React-Маршрутизатор 3.X. x с 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.х.х,<Link> сам компонент использует router.push, так что вы можете передать его все, что вы передадите <Link to= тег, например:

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

Реагировать Маршрутизатор V4

tl: dr;

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

простой и декларативный ответ заключается в том, что вам нужно использовать <Redirect to={URL} push={boolean} /> в сочетании с setState()

push: boolean - когда true, перенаправление будет толкать новую запись в историю вместо замены текущей.


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+ для инициализации состояния. Посмотри здесь а также, если вам интересно.


для компонентов ES6 + React для меня работало следующее решение.

я последовал за Фелиппе Скиннер, но добавил сквозное решение, чтобы помочь новичкам, как я.

Ниже приведены версии, которые я использовал:

"react-router": "^2.7.0"

"react": "^15.3.1"

ниже мой компонент react, где я использовал программную навигацию с помощью react-router:

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

может быть, не лучший подход, но... Используя react-router v4, следующий текст может дать представление о некоторых.

в отображаемом компоненте ниже, например LoginPage, router объект доступен и просто вызовите router.transitionTo('/homepage') перейти.

навигационный код взят из https://react-router.now.sh/Match.

"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')
);

сделать навигацию программно, вам нужно нажать новый история до бутафория.история в своем 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-маршрутизатор v4 и ЕС6

можно использовать 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);

на основе предыдущего ответа
от Хосе Антонио Постиго и Бена Уилера
новизна? должно быть написано машинопись
и использование декораторы
Или статический свойство/поле

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"


с 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"/>

реагировать-lego пример приложения, которое показывает как использовать / обновить react-router и он включает в себя примеры функциональных тестов, которые перемещаются по приложению.


С текущей версией React (15.3),this.props.history.push('/location'); работал для меня, но он показал следующее предупреждение:

браузер.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;

Если вы используете хэш или историю браузера, то вы можете сделать

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

использовать withRouter С компонентом на основе класса попробуйте что-то вроде этого ниже. Не забудьте изменить инструкцию export для использования 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);

React-Маршрутизатор V4

Если вы используете версию 4, то вы можете использовать мою библиотеку (промоушен), где вы просто отправить иск и все просто работает!

dispatch(navigateTo("/aboutUs"));

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


в маршрутизаторе react V4. Я следую этим двум путям программного маршрута.

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

номер два

заменяет текущую запись в стеке истории

чтобы получить историю в реквизите, вам может потребоваться обернуть компонент с помощью

withRouter https://reacttraining.com/react-router/core/api/withRouter


пожалуйста, найдите ниже код, который работает: Как обсуждалось в в этой статье, это очень простой способ навигации с помощью react Router:

class Register extends React.Component {
  state = {
    toDashboard: false,
  }
  handleSubmit = (user) => {
    saveUser(user)
      .then(() => this.setState(() => ({
        toDashboard: true
      })))
  }
  render() {
    if (this.state.toDashboard === true) {
      return <Redirect to='/dashboard' />
    }

    return (
      <div>
        <h1>Register</h1>
        <Form onSubmit={this.handleSubmit} />
      </div>
    )
  }
}

редирект / > is

составное декларативное пользовательское событие - > изменение состояния- > рендеринг

компонент Register визуализируется маршрутизатором React, наш код может выглядеть так

class Register extends React.Component {
  handleSubmit = (user) => {
    saveUser(user).then(() =>
      this.props.history.push('/dashboard')
    ))
  }
  render() {
    return (
      <div>
        <h1>Register</h1>
        <Form onSubmit={this.handleSubmit} />
      </div>
    )
  }
}

добавив withRouter, это будет выглядеть такой

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

class Register extends React.Component {
  handleSubmit = (user) => {
    saveUser(user).then(() =>
      this.props.history.push('/dashboard')
    ))
  }
  render() {
    return (
      <div>
        <h1>Register</h1>
        <Form onSubmit={this.handleSubmit} />
      </div>
    )
  }
}

export default withRouter(Register)

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


правильный ответ был для меня на момент написания статьи

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

но вам нужно добавить Проптипы в свой компонент

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

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

import PropTypes from 'prop-types';

возможно, не лучшее решение, но оно выполняет свою работу:

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 может быть нежелательно.

тем не менее, этот тип перенаправления не требуется так часто. Таким образом, одна или две дополнительные скрытые ссылки в разметке компонента не повредят, особенно если вы дадите им значимые имена.


Если произойдет пара RR4 w / redux через react-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 для управления асинхронным потоком, импортируйте вышеуказанных создателей действий в Redux actions и hook to react components с помощью mapDispatchToProps.


просто использовать this.props.history.push('/where/to/go');