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

967

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

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

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

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

  • 14
    @SergioTapia имейте в виду, что этот вопрос стоит в одном ряду с основным выпуском response-router, основным выпуском React и основным выпуском javascript
  • 1
    Вот ссылка на учебное пособие в официальных документах Реактивного маршрутизатора v4: reacttraining.com/react-router/web/guides/scroll-restoration
Показать ещё 4 комментария
Теги:
react-router

29 ответов

793
Лучший ответ

React Router v4

В версии 4 React Router существует три подхода к программной маршрутизации внутри компонентов.

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

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

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

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

1. Используйте withRouter высшего порядка withRouter

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. Используйте композицию и визуализируйте <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 есть раздел " Почему не использовать контекст" в их документации. Так что используйте на свой страх и риск!

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

  • 18
    Я попытался использовать метод 1 таким способом withRouter (({history}) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Но это никогда не работало с маршрутизатором 4
  • 0
    @DmitryMalugin Я не уверен, что этот код должен делать. Если вы просто хотите, чтобы компонент перемещался при монтировании, создайте <Redirect> .
Показать ещё 11 комментариев
739

React-Router 4.0. 0+ Ответ

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

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

React-Router 3.0. 0+ Ответ

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

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

React-Router 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-Router 2.0. 0+ Ответ

Эта версия обратно совместима с 1.x, поэтому нет необходимости в Руководстве по обновлению. Просто пройтись по примерам должно быть достаточно хорошо.

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

import { browserHistory } from 'react-router'

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

browserHistory.push('/some/path')

Дальнейшее чтение: истории и навигация


React-Router 1.xx Ответ

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

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

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

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

Обратите внимание, что эта History происходит от проекта rackt/history. Не от самого React-Router.

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

Или вы можете попробовать модный class ES6

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

Реагировать-маршрутизатор-Redux

Примечание: если вы используете Redux, есть еще один проект, называемый React-Router-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>
  • 0
    посмотрите на реализацию Navigation.transitionTo , вы очень часто звоните .context .
  • 0
    Ссылка в вашем ответе пошла 404.
Показать ещё 11 комментариев
502

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, а не для перехода на страницу.

  • 13
    Не забывайте, что более новый API не использует import { browserHistory } from './react-router' но вместо этого создает историю, используя import createBrowserHistory from 'history/lib/createBrowserHistory' . Позже вы можете получить доступ к history из реквизита компонентов: this.props.history('/some/path')
  • 0
    Но ... но ... как мне двигаться назад ?
Показать ещё 12 комментариев
44

Вот как вы делаете это с 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
}
  • 4
    Я полагаю, что текущая рекомендация состоит в том, чтобы использовать синглтон history как заявлено @Bobby. Вы можете использовать context.router но вы действительно затрудняете модульное тестирование этих компонентов, поскольку создание экземпляра только того компонента не будет иметь этого в контексте.
  • 1
    @ GeorgeMauer Я думаю, это зависит от того, где работает код. Согласно действующим документам, рекомендуется использовать context.router, если он запускается на сервере. github.com/reactjs/react-router/blob/master/upgrade-guides/...
28

Для этого, кто не контролирует серверную часть и из-за этого использует hash router 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()
  }
})
  • 0
    Благодарю. Может быть, я что-то упустил. Разве это не то же самое, что два верхних ответа?
  • 1
    Когда вы используете навигацию «по хешу», в «реакции-маршрутизаторе» v2 вам нужно установить дополнительный модуль «история» (если вы хотите избежать странных запросов к хешу), и вместо использования browserHistory вам нужно использовать useRouterHistory (createHashHistory) ( {queryKey: false}). Это главная причина, почему я написал это. Я показал, как ориентироваться в истории хешей.
Показать ещё 3 комментария
26

React-Router 4.x Ответ:

С моей стороны, мне нравится иметь единственный объект истории, который я могу нести даже за пределами компонентов. Мне нравится иметь один файл history.js, который я импортирую по требованию, и просто манипулировать им.

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

Вам нужно установить историю, библиотеку, которую использует 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>;
    }
}

РЕДАКТИРОВАТЬ 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>;
    }
}
  • 1
    За исключением документов React Router, которые говорят нам, что в большинстве случаев вам не нужно использовать Router вместо BrowserRouter . BrowserRouter создает и поддерживает объект history для вас. Вы не должны по умолчанию создавать свои собственные, только если вам ["нужна глубокая интеграция с инструментами управления состоянием, такими как Redux." ) Acttraining.com/react-router/web/api/Router
  • 1
    Это то, что я узнал со временем и опытом. Хотя обычно по умолчанию рекомендуется использовать this.props.history по умолчанию, я пока не нашел решения, которое могло бы помочь мне сделать такую вещь в классе, который не является компонентом, или любой другой инструмент, который не построен как компонент React, к которому вы можете передавать реквизит. Спасибо за ваш отзыв :)
23

Предупреждение: этот ответ охватывает только версии 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.

21

React Router V4

ТЛ: д-р;

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

  • 0
    Это лучший ответ, который я нашел. Использование withRouter не работало, когда уже на маршруте, который перезагружается. В нашем случае нам пришлось либо выборочно выполнить setState (вызывая return <Redirect> ), если он уже есть на маршруте, либо history.push() из другого места.
  • 0
    Очень, очень умный. И все же очень просто. Tks. Я использовал его внутри ReactRouterTable, так как хотел обрабатывать щелчок по всей строке. Используется на onRowClick для установки состояния. setState ({navigateTo: "/ path /" + row.uuid});
19

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

@Felipe Skinner 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 комментарий
15

Чтобы выполнить навигацию программно, вам нужно добавить новую историю в 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;
  • 0
    Пожалуйста, напишите версию реакции-роутера
15

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

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

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

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

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

В представленном компоненте ниже, например. Объект 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')
);
  • 1
    Почему вы не используете withRouter и browserHistory?
  • 1
    @ Erwin API отличается в v4. Смотрите этот github.com/ReactTraining/react-router/issues/3847 .
Показать ещё 2 комментария
12

В 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);
  • 1
    Уже упоминалось в нескольких других ответах (в том числе подробно в верхнем ответе)
10

Чтобы использовать 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);
9

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

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

< Redirect/> есть

Композитный Декларативный Пользовательское событие → Изменение состояния → Повторная визуализация

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

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 Router - и history.push. То, что вы используете, в основном зависит от вас и вашего конкретного случая использования, хотя я стараюсь отдавать предпочтение Redirect.

8

основываясь на предыдущем ответе
от Хосе Антонио Постиго и Бена Уилера
новинка? должен быть написан в 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. "response-router": "^ 3.0.0" и
"@types/реакции-маршрутизатор": "^ 2.0.41"

8

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

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

  • 5
    Это отлично подходит для навигации из функции рендера, хотя мне интересно, как перейти от чего-то вроде ловушки жизненного цикла или избыточности?
7

В реакции роутера v4. Я следую этому двухстороннему маршруту программно.

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

Номер два

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

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

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

6

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

hashHistory.push('/login');
browserHistory.push('/login');
  • 1
    hashHistory.push , дает Cannot прочитать свойство "push" из неопределенного. Откуда вы их импортируете?
  • 0
    import {hashHistory} из "реакции-маршрутизатора"; Вы можете импортировать его таким образом вверху.
Показать ещё 1 комментарий
6

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

browser.js: 49 Предупреждение: [ props.history -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');
4

React-Router V4

если вы используете версию 4, тогда вы можете использовать мою библиотеку (Shameless plug), где вы просто отправляете действие, и все просто работает!

dispatch(navigateTo("/aboutUs"));

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

3

Если случится с парой RR4 с редуктом через response -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 и подключайте для реагирования компоненты, используя mapDispatchToProps.

  • 1
    react-router-redux давно устарел / заархивирован
2

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

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

Но вам нужно добавить PropTypes в ваш компонент

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

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

import PropTypes from 'prop-types';
  • 0
    Пожалуйста, запишите версию реакции-роутера, и что вы импортировали из реактив-роутера
  • 0
    Ничего не импортировать, и это версия «ero-router »:« ^ 4.2.0 »
2

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

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

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

  • 0
    Можете ли вы объяснить, почему вы бы использовали это по сравнению с принятым решением?
  • 0
    Это просто альтернативное решение обсуждаемой проблемы. Как уже говорилось, не идеально, но он прекрасно работает для программных перенаправлений.
0

Те, кто сталкивается с проблемами в реализации этого на реакции-маршрутизатор 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>

another_file.js ИЛИ редукционный файл

import history from './history' 

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

Все благодаря этому комментарию: https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248

0

В зависимости от , где вы хотите перенаправить. Если внутри компонента, то ответ @Paul S - лучший способ сделать это.

Но если вы хотите перенаправить из любого места внутри приложения, я рекомендую использовать react-router-redux

0

Вы можете использовать этот метод другим компонентом.

toProfile() {
   this.context.history.pushState(null, 'profile');
}

и добавьте функцию onClick

<li onClick={this.toProfile.bind(this)></li>

надеюсь, что это полезно для вас.

-3

Просто используйте this.props.history.push('/where/to/go');

-10

Вы можете использовать

document.location.hash = 'path'

Примечания:

  • Это статический строковый путь.
  • История добавляется правильно с этим.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню