web-dev-qa-db-ja.com

反応ルーターV4を使用してプログラムでナビゲートする

react-routerをv3からv4に置き換えました。
しかし、私はプログラム的にComponent。のメンバー関数内をナビゲートする方法がわからない、すなわちhandleClick()関数内でデータを処理した後に/path/some/whereにナビゲートしたいのですが。次のようにしてください。

import { browserHistory } from 'react-router'
browserHistory.Push('/path/some/where')

しかし、私はv4ではそのようなインターフェースを見つけることができません。
v4を使って移動するにはどうすればいいですか?

256
Colin Witkamp

それを成し遂げる最も簡単な方法:

this.props.history.Push("/new/url")

注意:

  • historypropを親コンポーネントからアクションを呼び出したいコンポーネントまで渡すことができます。
117
Jikku Jose

React-Router v4への移行時にも同様の問題がありましたので、以下で解決策を説明します。

この答えをこの問題を解決する正しい方法とは見なさないでください。ReactRouter v4が成熟してベータ版が完成するにつれて、もっと良いことが起こる可能性が高いと思います(それはすでに存在しているので、発見できませんでした)。 。

文脈では、私は時折Redux-Sagaを使って歴史的オブジェクトをプログラム的に変更するので(ユーザーが正常に認証されたときなど)、この問題がありました。

React Routerのドキュメントで、<Router>component を見てください。あなたはあなた自身の履歴オブジェクトを小道具を通して渡す能力を持っていることがわかります。これが解決策の本質です - historyオブジェクトを提供global モジュールからReact-Routerへ。

ステップ:

  1. History npmモジュールをインストールします - yarn add historyまたはnpm install history --save
  2. history.jsレベルのフォルダーにApp.jsというファイルを作成します(これが私の好みでした)。

    // src/history.js
    
    import createHistory from 'history/createBrowserHistory';
    export default createHistory();`
    
  3. この履歴オブジェクトをルーターコンポーネントに以下のように追加してください。

    // src/App.js
    
    import history from '../your/path/to/history.js;'
    <Router history={history}>
    // Route tags here
    </Router>
    
  4. 以前のように あなたの グローバル履歴オブジェクトをインポートしてURLを調整します。 

    import history from '../your/path/to/history.js;'
    history.Push('new/path/here/');
    

今はすべて同期しているはずです。また、コンポーネントやコンテナを介してではなく、プログラムで履歴オブジェクトを設定する方法にアクセスすることもできます。

49
Alex Mann

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 + Property Initializers を使用して状態を初期化します。興味があるなら here も見てください。

36
Lyubomir

ステップ1:一番上にインポートするものが1つだけあります。 

    import {Route} from 'react-router-dom';

ステップ2:あなたのルートで、歴史を渡します:

    <Route exact path='/posts/add' render={({history})  => (
      <PostAdd
        history={history}
      />
    .)}/>

ステップ3:履歴は次のコンポーネントの小道具の一部として受け入れられるので、単純に次のことができます。 

    this.props.history.Push('/');

それは簡単で本当に強力でした。

7
cdi-meo

単に小道具を使うこともできます:this.props.history.Push('new_url')

6
user1445685

これは動作します:

import { withRouter } from 'react-router-dom';

const SomeComponent = withRouter(({ history }) => (
    <div onClick={() => history.Push('/path/some/where')}>
        some clickable element
    </div>); 
);

export default SomeComponent;
6
Kaya Toast

私の答えは Alex's に似ています。なぜReact-Routerがこれを必要以上に複雑にしたのかはわかりません。本質的にグローバルなものにアクセスするためだけにコンポーネントをHoCでラップする必要があるのはなぜですか? 

とにかく、あなたが <BrowserRouter> をどのように実装したかを見れば、 history のまわりの小さなラッパーです。

その履歴を少し引き出して、どこからでもインポートできるようにすることができます。ただし、トリックは、サーバーサイドのレンダリングを行っているときにhistoryモジュールをimportにしようとすると、ブラウザのみのAPIを使用するため機能しません。しかし、それは問題ありません。通常、クリックやその他のクライアントサイドのイベントに応答してリダイレクトするだけです。そのため、おそらくそれを偽造しても問題ありません。

// history.js
if(__SERVER__) {
    module.exports = {};
} else {
    module.exports = require('history').createBrowserHistory();
}

Webpackの助けを借りて、いくつかの変数を定義することができるので、自分がどの環境にいるのかを知ることができます。

plugins: [
    new DefinePlugin({
        '__SERVER__': 'false',
        '__BROWSER__': 'true', // you really only need one of these, but I like to have both
    }),

そして今、あなたはできる

import history from './history';

どこからでも。サーバー上で空のモジュールが返されるだけです。

これらの魔法の変数を使用したくない場合は、グローバルオブジェクトの必要な場所(イベントハンドラ内)でrequireを実行するだけです。 importはトップレベルでしか機能しないので機能しません。

5
mpen

私は数日間v4をテストしています、そして、私は今のところそれを愛しています!しばらくしてから意味があります。

私も同じ質問をしました、そして、私は以下のようにそれを扱うことが最もうまくいった(そしてそれが意図される方法でさえあるかもしれません)のがわかりました。 state、三項演算子、<Redirect>を使います。

コンストラクタ()内

this.state = {
    redirectTo: null
} 
this.clickhandler = this.clickhandler.bind(this);

Render()の中で 

render(){
    return (
        <div>
        { this.state.redirectTo ?
            <Redirect to={{ pathname: this.state.redirectTo }} /> : 
            (
             <div>
               ..
             <button onClick={ this.clickhandler } />
              ..
             </div>
             )
         }

クリックハンドラ()内

 this.setState({ redirectTo: '/path/some/where' });

それが役に立てば幸い。お知らせ下さい。

4
jar0m1r

この恐ろしいデザインに対処する他の方法がないので、私はwithRouter_ hoc _ アプローチを使う一般的なコンポーネントを書きました。以下の例はbutton要素をラップしていますが、必要なクリック可能要素に変更することができます。

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';

const NavButton = (props) => (
  <Button onClick={() => props.history.Push(props.to)}>
    {props.children}
  </Button>
);

NavButton.propTypes = {
  history: PropTypes.shape({
    Push: PropTypes.func.isRequired
  }),
  to: PropTypes.string.isRequired
};

export default withRouter(NavButton);

使用法:

<NavButton to="/somewhere">Click me</NavButton>
3
Rodrigo

ReactJSはWebアプリケーションを書くためのまったく異なる方法であるため、私はしばらくの間苦労しました。

私は混乱を取り除くために別のコンポーネントを作成しました。

// LinkButton.js

import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';

export default class LinkButton extends React.Component {

    render() {
        return (
            <Route render={({history}) => (
                <button {...this.props}
                       onClick={() => {
                           history.Push(this.props.to)
                       }}>
                    {this.props.children}
                </button>
            )}/>
        );
    }
}

LinkButton.propTypes = {
    to: PropTypes.string.isRequired
};

それをrender()メソッドに追加します。

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>
2
mwieczorek

私は@ rgommezzがほとんどの場合をカバーしていると思います - 私はそれが非常に重要であると思うものから1を引いたものです。 

// history is already a dependency or React Router, but if don't have it then try npm install save-dev history

import createHistory from "history/createBrowserHistory"

// in your function then call add the below 
const history = createHistory();
// Use Push, replace, and go to navigate around.
history.Push("/home");

これは私が私のコンポーネントに多くのHoCをすることなく私が欲しい任意のコンポーネントからナビゲーションをするために呼び出すことができるアクション/呼び出しで単純なサービスを書くことを可能にします... 

これまでに誰もこのソリューションを提供したことがないのかは明らかではありません。それが助けになることを願っています、そして、あなたがそれに問題があるのを見つけたならば、私に知らせてください。

2
user3053247

時々私はアプリケーションによってそれからボタンによってルートを切り替えるのを好むように、これは私のために働く最低限の実用的な例です:

import { Component } from 'react'
import { BrowserRouter as Router, Link } from 'react-router-dom'

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

    /** @type BrowserRouter */
    this.router = undefined
  }

  async handleSignFormSubmit() {
    await magic()
    this.router.history.Push('/')
  }

  render() {
    return (
      <Router ref={ el => this.router = el }>
        <Link to="/signin">Sign in</Link>
        <Route path="/signin" exact={true} render={() => (
          <SignPage onFormSubmit={ this.handleSignFormSubmit } />
        )} />
      </Router>
    )
  }
}
1
piotr_cz

React RouterまたはReact Router Domを使用してルーターを完全に初期化する前にリダイレクトする必要があるあなたのためにあなたは単にhistoryオブジェクトにアクセスしてapp.jsのコンストラクタ内でそれに新しい状態をプッシュすることによってリダイレクトを提供できます。次の点を考慮してください。

function getSubdomain(hostname) {
    let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
    let urlParts = regexParse.exec(hostname);
    return hostname.replace(urlParts[0], '').slice(0, -1);
}

class App extends Component {

    constructor(props) {
        super(props);


        this.state = {
            hostState: true
        };

        if (getSubdomain(window.location.hostname).length > 0) {
            this.state.hostState = false;
            window.history.pushState('', '', './login');
        } else {
            console.log(getSubdomain(window.location.hostname));
        }

    }


    render() {
        return (

            <BrowserRouter>
                {this.state.hostState ? (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                        <Route path="/" component={PublicContainer}/>
                    </div>
                ) : (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                    </div>
                )

                }
            </BrowserRouter>)
    }


}

ここでは、コンポーネントがレンダリングする前にhistoryオブジェクトと対話することによって、サブドメインに依存する出力Routesを変更したいと思います。

window.history.pushState('', '', './login');
0
li x