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

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

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

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

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

51 ответ

Решение

React Router v4

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

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

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 Ответ

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

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

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

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

Обратите внимание, что это 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

Или вы можете попробовать модную 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
};

Реагировать-маршрутизатор-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>

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

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

РЕДАКТИРОВАТЬ 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>;
    }
}

Вот как вы делаете это с 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
}

Для этого, кто не контролирует серверную часть и из-за этого использует 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()
  }
})

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

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

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

@ Филип Скиннер 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'})'

Чтобы выполнить навигацию программно, вам нужно добавить новую историю в 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;

Для компонентов 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'));

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

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

Номер два

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

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

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

Возможно, это не лучший подход, но... С помощью 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')
);

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

Использовать 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);

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

Основываясь на предыдущем ответе
от Хосе Антонио Постиго и Бена Уилера
новинка? должен быть написан в 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"

Для тех, кто уже использует React Router v6, это можно сделать с помощью useNavigateкрючок, предоставленный react-router.

Навигация с помощью этого хука довольно проста:

      import { generatePath, useNavigate } from 'react-router';

navigate(-1); // navigates back
navigate('/my/path'); // navigates to a specific path
navigate(generatePath('my/path/:id', { id: 1 })); // navigates to a dynamic path, generatePath is very useful for url replacements

Для последней версии react-router-dom v6

useHistory()заменяется на useNavigate().

Вам нужно использовать:

      import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
navigate('/your-page-link');

Обновление: React Router v6 с хуками

import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
navigate('home');

И чтобы перемещаться по истории браузера,

navigate(-1); ---> Go back
navigate(1);  ---> Go forward
navigate(-2); ---> Move two steps backward.

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

browser.js: 49 Предупреждение: [реагирует на маршрутизатор] 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');

React-Router V4

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

dispatch(navigateTo("/aboutUs"));

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

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

файл other_file.js/redux

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

Вы также можете использовать 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

Программная навигация в компонентах на основе классов.

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

class MyComponent extends React.Component{
    state= {rpath: null}

    const goTo= (path)=> this.setState({rpath: path});

    render(){
        if(this.state.rpath){
            return <Redirect to={this.state.rpath}/>
        }
        .....
        .....
    }
}

Надеюсь, поможет.

Итак, в моем ответе есть 3 разных способа программного перенаправления на маршрут. Некоторые решения уже были представлены, а следующие ориентированы только на функциональные компоненты с дополнительным демонстрационным приложением.

Используя следующие версии:

реагировать: 16.13.1

реагировать-дом: 16.13.1

реагировать-маршрутизатор: 5.2.0

реагировать-маршрутизатор-дом: 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 hook дает нам доступ к объекту истории, который помогает нам программно перемещаться или изменять маршруты.

  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 props для обернутого компонента всякий раз, когда он отрисовывается.

Демо:

Для лучшего представления я создал репозиторий GitHub с этими примерами, вы можете найти его ниже:

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

Надеюсь, это поможет!

Если случится с парой RR4 с редуксом через Reaction -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.

Вместо этого используйте hookrouter, современную альтернативу response-router

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

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

чтобы ответить на вопрос OP о связывании через поле выбора, вы можете сделать это:

navigate('/about');

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

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

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

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