React-router: Як вручну викликати Link?


131

Я новачок у ReactJS та React-Router. У мене є компонент, який отримує через реквізит <Link/>об'єкт від react-router . Щоразу, коли користувач натискає кнопку "наступний" всередині цього компонента, я хочу викликати <Link/>об'єкт вручну.

Зараз я використовую refs для доступу до екземпляра резервного копіювання та вручну натискаю на тег 'a', який <Link/>створюється.

Питання: Чи існує спосіб вручну викликати Посилання (наприклад this.props.next.go)?

Це поточний код у мене:

//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />

//in Document.js
...
var Document = React.createClass({
   _onClickNext: function() {
      var next = this.refs.next.getDOMNode();
      next.querySelectorAll('a').item(0).click(); //this sounds like hack to me
   },
   render: function() {
      return (
         ...
         <div ref="next">{this.props.next} <img src="rightArrow.png" onClick={this._onClickNext}/></div>
         ...
      );
   }
});
...

Це код, який я хотів би мати:

//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />

//in Document.js
...
var Document = React.createClass({
   render: function() {
      return (
         ...
         <div onClick={this.props.next.go}>{this.props.next.label} <img src="rightArrow.png" /> </div>
         ...
      );
   }
});
...

Відповіді:


199

React Router v4 - компонент перенаправлення (оновлено 2017/04/15)

Рекомендований v4 спосіб - дозволити вашому методу візуалізації зловити переадресацію. Використовуйте стан або реквізит, щоб визначити, чи потрібно показувати компонент переадресації (який потім тригер - це переадресація).

import { Redirect } from 'react-router';

// ... your class implementation

handleOnClick = () => {
  // some action...
  // then redirect
  this.setState({redirect: true});
}

render() {
  if (this.state.redirect) {
    return <Redirect push to="/sample" />;
  }

  return <button onClick={this.handleOnClick} type="button">Button</button>;
}

Довідка: https://reacttraining.com/react-router/web/api/Redirect

Реактивний маршрутизатор v4 - контекст опорного маршрутизатора

Ви також можете скористатися Routerконтекстом, який піддається впливу компонента React.

static contextTypes = {
  router: PropTypes.shape({
    history: PropTypes.shape({
      push: PropTypes.func.isRequired,
      replace: PropTypes.func.isRequired
    }).isRequired,
    staticContext: PropTypes.object
  }).isRequired
};

handleOnClick = () => {
  this.context.router.push('/sample');
}

Так <Redirect />працює під кришкою.

Довідка: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Redirect.js#L46,L60

Реактивний маршрутизатор v4 - зовнішній мутаційний об'єкт історії

Якщо вам все-таки потрібно зробити щось подібне до впровадження v2, ви можете створити копію, BrowserRouterа потім викласти експозицію historyяк константу, що експортується. Нижче наведено основний приклад, але ви можете скласти його, щоб ввести його за допомогою налаштованих реквізитів, якщо це необхідно. Існують помітні застереження з життєвими циклами, але він повинен завжди відтворювати маршрутизатор, як і в v2. Це може бути корисно для переадресації після запиту API від дії функції.

// browser router file...
import createHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';

export const history = createHistory();

export default class BrowserRouter extends Component {
  render() {
    return <Router history={history} children={this.props.children} />
  }
}

// your main file...
import BrowserRouter from './relative/path/to/BrowserRouter';
import { render } from 'react-dom';

render(
  <BrowserRouter>
    <App/>
  </BrowserRouter>
);

// some file... where you don't have React instance references
import { history } from './relative/path/to/BrowserRouter';

history.push('/sample');

Останні BrowserRouterрозширення: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/BrowserRouter.js

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

Натисніть на новий browserHistoryекземпляр:

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

Довідка: https://github.com/reactjs/react-router/blob/master/docs/guides/NavigatingOutsideOfComponents.md


7
hashHistory.push ('/ sample'); якщо ви використовуєте hashHistory замість браузераHistory
sanath_p

1
це особливо корисно в бібліотеці матеріалів ui, оскільки використання контейнераElement = {<Посилання на = "/" />} не завжди посилається на посилання
Vishal Disawar

2
Зверніть увагу на опцію переадресації, ви повинні вказати push (тобто <Переадресація />). За замовчуванням вона зробить заміну, яка зовсім не така, як виклик посилання вручну
aw04

1
@jokab ви можете використовувати <NavLink /> замість <Посилання /> github.com/ReactTraining/react-router/blob/master/packages/…
Matt Lo

1
Перенаправлення не працює для мене, але рішення aw04 з withRouter є більш простим і працюючим
stackdave

90

Маршрутизатор React 4 включає в себе HOC withRouter, який надає вам доступ до historyоб'єкта через this.props:

import React, {Component} from 'react'
import {withRouter} from 'react-router-dom'

class Foo extends Component {
  constructor(props) {
    super(props)

    this.goHome = this.goHome.bind(this)
  }

  goHome() {
    this.props.history.push('/')
  }

  render() {
    <div className="foo">
      <button onClick={this.goHome} />
    </div>
  }
}

export default withRouter(Foo)

9
Це працювало для мене, і це виглядає як найпростіше рішення.
Rubycut

5
Це найкраще рішення. Я не розумію, чому у неї так мало голосів.
Бенуа

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

@VladyslavTereshyn ви можете додати деяку умовну логіку: якщо ((this.props.location.pathname + this.props.location.search)! == navigateToPath) {...}
MattWeiler

15

У версії 5.x ви можете використовувати useHistoryгачок react-router-dom:

// Sample extracted from https://reacttraining.com/react-router/core/api/Hooks/usehistory
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>
  );
}

Це найкраще рішення. Якщо ви додасте деяку умовну логіку, ви можете уникнути повторюваних записів в історії, коли користувач кілька разів натискає ту саму кнопку:if ((routerHistory.location.pathname + routerHistory.location.search) !== navigateToPath) { routerHistory.push(navigateToPath); }
MattWeiler

Мені потрібно було оголосити historyзмінну, виклик каталогів useHistory().pushзаборонено правилами гаків
onmyway133

це здається найсучаснішим реагуючим рішенням.
Youngjae

8

https://github.com/rackt/react-router/blob/bf89168acb30b6dc9b0244360bcbac5081cf6b38/examples/transitions/app.js#L50

або ви навіть можете спробувати виконати onClick це (більш жорстоке рішення):

window.location.assign("/sample");

У міру зміни рядків коду ваша відповідь буде кращою, якщо ви скопіюєте деталі та поясните свою відповідь тут. Крім того, assignце не властивість, це функція.
WiredPrairie

(Але ви все ще просто маєте посилання на певний рядок файлу). Будь ласка, включіть у відповідь конкретну пропозицію, а не лише посилання.
WiredPrairie

Дякуємо за вашу відповідь @grechut. Однак я хочу переконатися, що Document взагалі нічого не знає про роутер. Поведінка, яку я очікую: "Якщо користувач натискає стрілку праворуч, викликайте наступну функцію". Наступною функцією може бути посилання чи ні.
Алан Суза

У мене є декілька сторінок, які обробляються за межами React (екрани входу за допомогою переспрямувань FB і Google), тому мені знадобилося це у навігаційному режимі для цих сторінок, оскільки "browserHistory.push ('/ home');" лише змінила URL-адресу, вона не змогла прокладати сторінки. Дякую.
Дебора

7
Це перезавантажить сторінку @grechut, а не бажану поведінку для програми з маршрутизатором реагування.
Абхас

2

Гаразд, я думаю, що мені вдалося знайти правильне рішення для цього.

Тепер, замість того, щоб відправляти <Link/>як опору до Document, я надсилаю <NextLink/>котрий є власною обгорткою для Link-маршрутизатора. Роблячи це, я можу мати стрілку вправо як частину структури посилання, уникаючи при цьому коду маршрутизації всередині об'єкта Document.

Оновлений код виглядає так:

//in NextLink.js
var React = require('react');
var Right = require('./Right');

var NextLink = React.createClass({
    propTypes: {
        link: React.PropTypes.node.isRequired
    },

    contextTypes: {
        transitionTo: React.PropTypes.func.isRequired
    },

    _onClickRight: function() {
        this.context.transitionTo(this.props.link.props.to);
    },

    render: function() {
        return (
            <div>
                {this.props.link}
                <Right onClick={this._onClickRight} />
            </div>  
        );
    }
});

module.exports = NextLink;

...
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
var nextLink = <NextLink link={sampleLink} />
<Document next={nextLink} />

//in Document.js
...
var Document = React.createClass({
   render: function() {
      return (
         ...
         <div>{this.props.next}</div>
         ...
      );
   }
});
...

PS : Якщо ви використовуєте останню версію реактор-маршрутизатора, можливо, вам доведеться використовувати this.context.router.transitionToзамість цього this.context.transitionTo. Цей код буде добре працювати для реактор-маршрутизатора версії 0.12.X.


2

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

Ви можете легко викликати метод push через контекст в v4:

this.context.router.push(this.props.exitPath);

де контекст:

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

Використовуючи BrowserRouter, контекстний об'єкт моїх компонентів не містить routerоб'єкта. Я роблю щось не так?
pilau

Ви встановлюєте контекст у компоненті (другий блок вище)?
Кріс

Дякуємо, що причалили! в кінці кінців , це працювало для мене router: React.PropTypes.object.isRequired. Я не знаю, чому не обійшлося без isRequiredключа. Також, <Link>схоже, вдалося отримати historyконтекст, але я не зміг його повторити.
pilau

Цікавий - якщо ви поставите кодек, я можу допомогти вам налагодити його, якщо ви все-таки застрягли
Кріс

Схоже, ви можете використовувати this.props.history.push()в React Router v4. Я виявив це лише оглянувши реквізит, через який проходить маршрутизатор React. Здається, це працює, але я не впевнений, чи це гарна ідея.
sean_j_roberts

-1

знову це JS :) це все ще працює ....

var linkToClick = document.getElementById('something');
linkToClick.click();

<Link id="something" to={/somewhaere}> the link </Link>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.