Программная навигация с помощью маршрутизатора react
С react-router
можно использовать Link
элемент для создания ссылок, которые изначально обрабатываются маршрутизатором react.
Я вижу внутренне он называет this.context.transitionTo(...)
.
Я хочу сделать навигацию, но не по ссылке, например, из выпадающего списка. Как я могу сделать это в коде? Что такое this.context
?
Я видел Navigation
mixin, но могу ли я сделать это без mixins?
25 ответов
реагировать маршрутизатор v4
С v4 маршрутизатора React существует три подхода, которые можно использовать для программной маршрутизации внутри компонентов.
- использовать
withRouter
выше-того компонента. - используйте композицию и визуализируйте
<Route>
- использовать
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"));
в маршрутизаторе 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.