reactjs - router教學 - redux router v3




使用react路由器以編程方式導航 (19)

使用 react-router 我可以使用 Link 元素創建由react路由器本地處理的鏈接。

我在內部看到它調用 this.context.transitionTo(...)

我想進行導航,但不是從鏈接,例如下拉選擇。 我怎麼能在代碼中這樣做? 這是什麼意思?

我看到了 Navigation mixin,但是我可以不使用mixin嗎?


反應路由器V4

TL:博士;

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

完整的例子。 here 閱讀更多。

PS。 該示例使用 ES7 +屬性初始化 程序初始化狀態。 如果你有興趣,也可以看看 here


對於React Router v4 +

假設您不需要在初始渲染本身(可以使用 <Redirect> 組件) 期間導航 ,這就是我們在應用程序中所做的。

定義一個返回null的空路由,這將允許您獲取對歷史對象的訪問權限。 您需要在 Router 定義了 您的頂層執行此操作 。

現在你可以做一切可以做的事 history 一樣 history.push()history.replace()history.go(-1) 等!

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

let routeHistory = null;

export function navigateTo(path) {
  if(routeHistory !== null) {
    routeHistory.push(path);
  }
}

export default function App(props) {
  return (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}

React-Router 4.0.0+ 答案

在4.0及更高版本中,使用歷史記錄作為組件的支柱。

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

注意:如果您的組件未由 <Route> 呈現,則this.props.history不存在。 您應該使用 <Route path="..." component={YourComponent}/> 在YourComponent中使用this.props.history

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'

現在您可以訪問瀏覽器歷史記錄,因此您可以執行推送,替換等操作...

browserHistory.push('/some/path')

進一步閱讀: HistoriesNavigation

React-Router 1.xx 答案

我不打算升級細節。 您可以在“ 升級指南”中 閱讀相關內容

這裡問題的主要變化是從導航mixin到History的變化。 現在它正在使用瀏覽器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 答案

我遇到了同樣的問題,只能通過react-router附帶的Navigation mixin找到解決方案。

這就是我做到的

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,還有另一個名為 React-Router-Redux ,它為ReactRouter提供了redux綁定,使用的方法與 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 4.x答案:

在我的結尾,我喜歡有一個歷史對象,我甚至可以攜帶外部組件。 我喜歡做的是擁有一個我按需導入的單個history.js文件,並且只是操作它。

您只需將 BrowserRouter 更改為Router,並指定歷史記錄。 這不會改變任何事情,除非你有自己的歷史對象,你可以根據需要進行操作。

您需要安裝 historyreact-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>;
    }
}

編輯2018年4月16日:

如果必須從實際從 Route 組件呈現的組件導航,您還可以從props訪問歷史記錄,如下所示:

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

反應路由器v4

使用React Router的v4,您可以採用三種方法在組件內進行編程路由。

  1. 使用 withRouter 高階組件。
  2. 使用合成並渲染 <Route>
  3. 使用 context

React Router主要是 history 庫的包裝器。 history 通過瀏覽器和哈希歷史處理與瀏覽器 window.history 交互。 它還提供了一個內存歷史記錄,對於沒有全局歷史記錄的環境非常有用。 這在移動應用程序開發( react-native )和Node的單元測試中特別有用。

history 實例有兩種導航方法: pushreplace 。 如果您將 history 視為已訪問位置的數組,則 push 將向陣列添加新位置,並且 replace 將使用新位置 replace 陣列中的當前位置。 通常,您需要在導航時使用 push 方法。

在早期版本的React Router中,您必須創建自己的 history 實例,但在第4版中, <BrowserRouter><HashRouter><MemoryRouter> 組件將為您創建瀏覽器,哈希和內存實例。 React Router通過路由器對像下的上下文使與路由器關聯的 history 實例的屬性和方法可用。

1.使用 withRouter 高階組件

withRouter 高階組件將 history 對象注入為組件的prop。 這允許您訪問 pushreplace 方法,而無需處理 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的 context 模型時才能使用的選項。 儘管上下文是一種選擇,但應該強調上下文是一個不穩定的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是最簡單的選擇,因此對於大多數用例來說,它們是您最好的選擇。


警告: 此答案僅涵蓋1.0之前的ReactRouter版本

我將用1.0.0-rc1用例更新此答案!

你也可以不用mixin來做到這一點。

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


也許不是最好的解決方案,但它完成了工作:

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組件中。

但是,通常不需要這種類型的重定向。 因此,組件標記中的一個或兩個額外的隱藏鏈接不會對此造成太大影響,特別是如果您給它們提供有意義的名稱。


只需使用 this.props.history.push('/where/to/go');


如果碰巧通過 react-router-redux 將RR4 w / 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鉤子來反應組件可能會更好。


這對我有用,不需要特殊進口:

<input type="button" name="back" id="back" class="btn btn-primary" value="Back" onClick={() => { this.props.history.goBack() }} />


以下是使用 react-router v2.0.0 ES6react-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
}

使用當前的React版本(15.3), this.props.history.push('/location'); 為我工作,但它顯示以下警告:

browser.js:49警告:[react-router] props.historycontext.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;

在事情正常之前我嘗試了至少10種方法!

@Felipe Skinner的回復對我來說有點壓倒性的,我不確定我是否想製作新的“ExportedWithRouter”類名。

這是最簡單,最乾淨的方法,大約是當前的React-Router 3.0.0和ES6:

帶有ES6的React-Router 3.xx:

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

在反應路由器v4中。 我按照這兩種方式以編程方式進行路由。

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

第二

替換歷史堆棧上的當前條目

要獲取道具的歷史記錄,您可能需要使用包裝

withRouter


對於ES6 + React組件,以下解決方案適用於我。

我跟著Felippe skinner,但添加了一個端到端的解決方案,以幫助像我這樣的初學者。

以下是我使用的版本:

“react-router”:“^ 2.7.0”

“反應”:“^ 15.3.1”

下面是我的反應組件,我使用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'));

對於這個,誰不控制服務器端,因此使用哈希路由器v2:

history 放入單獨的文件中(例如app_history.js ES6):

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

export default appHistory;

到處使用它!

您對react-router(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()
  }
})

要以編程方式進行導航,您需要將新 歷史記錄 送到 component props.history ,這樣這樣的事情可以為您完成工作:

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

要將 withRouter 與基於類的組件一起使用,請嘗試以下方法。 不要忘記更改要與 withRouter 一起使用的export語句:

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-redux程序。





react-router