React Router(v3)の現在のバージョンでは、私はサーバーの応答を受け入れてbrowserHistory.Push
を使って適切な応答ページに行くことができます。しかし、これはv4では利用できないので、これを処理する適切な方法が何であるかわかりません。
この例では、Reduxを使用して、 components/app-product-form.js がユーザーがフォームを送信したときにthis.props.addProduct(props)
を呼び出します。サーバーが成功を返すと、ユーザーはカートページに移動します。
// actions/index.js
export function addProduct(props) {
return dispatch =>
axios.post(`${ROOT_URL}/cart`, props, config)
.then(response => {
dispatch({ type: types.AUTH_USER });
localStorage.setItem('token', response.data.token);
browserHistory.Push('/cart'); // no longer in React Router V4
});
}
React Router v4の機能から[Cart]ページにリダイレクトする方法を教えてください。
あなたのコンポーネントの外でhistory
メソッドを使うことができます。次の方法で試してください。
まず、 履歴パッケージ を使ってhistory
オブジェクトを作成します。
// src/history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
それを<Router>
でラップします( 注意してください 、import { Router }
の代わりにimport { BrowserRouter as Router }
を使うべきです)
// src/index.jsx
// ...
import { Router, Route, Link } from 'react-router-dom';
import history from './history';
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/login">Login</Link></li>
</ul>
<Route exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
</div>
</Router>
</Provider>,
document.getElementById('root'),
);
現在地をどこからでも変更できます。次に例を示します。
// src/actions/userActionCreators.js
// ...
import history from '../history';
export function login(credentials) {
return function (dispatch) {
return loginRemotely(credentials)
.then((response) => {
// ...
history.Push('/');
});
};
}
UPD: React Router FAQ には、少し異なる例もあります。
React Router v4はv3(およびそれ以前)とは根本的に異なり、以前のようにbrowserHistory.Push()
を実行することはできません。
この議論 さらに情報が必要な場合は/に関連があるようです:
<BrowserRouter>
は独自の履歴インスタンスを作成し、それに対する変更をリッスンするため、新しいbrowserHistory
を作成してもうまくいきません。したがって、別のインスタンスがURLを変更しても<BrowserRouter>
は更新されません。- v4では
browserHistory
はreact-routerによって公開されず、v2でのみ公開されます。
代わりに、これを行うためのいくつかのオプションがあります。
withRouter
高次コンポーネントを使う代わりにwithRouter
高次コンポーネントを使用し、それを履歴にプッシュするコンポーネントにラップするべきです。例えば:
import React from "react";
import { withRouter } from "react-router-dom";
class MyComponent extends React.Component {
...
myFunction() {
this.props.history.Push("/some/Path");
}
...
}
export default withRouter(MyComponent);
詳しくは 公式ドキュメント をご覧ください。
history
オブジェクトのプロパティと最も近い<Route>
のmatch
にアクセスするには、withRouter高次コンポーネントを使います。 withRouterは、ルートが<Route>
render props:{ match, location, history }
と同じプロップで変更されるたびにそのコンポーネントを再レンダリングします。
context
APIを使用するコンテキストを使用するのが最も簡単な解決策の1つかもしれませんが、実験的なAPIであるため不安定でサポートされていません。他のすべてが失敗したときだけそれを使ってください。これが例です:
import React from "react";
import PropTypes from "prop-types";
class MyComponent extends React.Component {
static contextTypes = {
router: PropTypes.object
}
constructor(props, context) {
super(props, context);
}
...
myFunction() {
this.context.router.history.Push("/some/Path");
}
...
}
公式ドキュメント をコンテキストで見てください。
アプリケーションを安定させたい場合は、コンテキストを使用しないでください。これは実験的なAPIであり、将来のReactのリリースでは壊れる可能性があります。
これらの警告にもかかわらずコンテキストの使用を主張する場合は、コンテキストの使用を小さな領域に限定し、可能であればコンテキストAPIを直接使用しないようにしてください。
これが私のやり方です。
import React, {Component} from 'react';
export default class Link extends Component {
constructor(props) {
super(props);
this.onLogout = this.onLogout.bind(this);
}
onLogout() {
this.props.history.Push('/');
}
render() {
return (
<div>
<h1>Your Links</h1>
<button onClick={this.onLogout}>Logout</button>
</div>
);
}
}
履歴オブジェクトに保存されるカートページにリダイレクトするには、this.props.history.Push('/cart');
を使用します。
マイケル、お楽しみください。
React Router v4のドキュメントによると - Redux Deep Integrationセッション
以下の目的で、高度な統合が必要です。
「ディスパッチアクションでナビゲートできる」
しかしながら、彼らは「深い統合」の代わりとしてこのアプローチを推奨します。
「ナビゲートするアクションをディスパッチするのではなく、コンポーネントを自分のアクションにルーティングし、そこでナビゲートするために提供された履歴オブジェクトを渡すことができます。」
それで、あなたはあなたのコンポーネントをwithRouter高次コンポーネントで包むことができます:
export default withRouter(connect(null, { actionCreatorName })(ReactComponent));
履歴APIを小道具に渡します。それで、あなたはアクションクリエータを歴史としてパラメータとして渡していると呼ぶことができます。たとえば、あなたのReactComponentの中:
onClick={() => {
this.props.actionCreatorName(
this.props.history,
otherParams
);
}}
それから、actions/index.jsの中に:
export function actionCreatorName(history, param) {
return dispatch => {
dispatch({
type: SOME_ACTION,
payload: param.data
});
history.Push("/path");
};
}
厄介な質問ですが、かなり時間がかかりましたが、結局、私はこのようにして解決しました。
あなたのコンテナをwithRouter
でラップし、mapDispatchToProps
関数であなたのアクションに履歴を渡します。実際にはhistory.Push( '/ url')を使って移動します。
アクション:
export function saveData(history, data) {
fetch.post('/save', data)
.then((response) => {
...
history.Push('/url');
})
};
容器:
import { withRouter } from 'react-router-dom';
...
const mapDispatchToProps = (dispatch, ownProps) => {
return {
save: (data) => dispatch(saveData(ownProps.history, data))}
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container));
これは React Router v4.xに有効です 。
this.context.history.Push
は機能しません。
私はどうにかしてPushを次のように動作させました。
static contextTypes = {
router: PropTypes.object
}
handleSubmit(e) {
e.preventDefault();
if (this.props.auth.success) {
this.context.router.history.Push("/some/Path")
}
}
この場合は、小道具を小道具に渡しています。だからあなたは単に呼び出すことができます
props.history.Push('/cart')
そうでない場合でも、コンポーネントから履歴を渡すことができます。
export function addProduct(data, history) {
return dispatch => {
axios.post('/url', data).then((response) => {
dispatch({ type: types.AUTH_USER })
history.Push('/cart')
})
}
}
React Router 4の最も簡単な方法は使用することです
this.props.history.Push('/new/url');
しかし、このメソッドを使うためには、あなたの existing コンポーネントはhistory
オブジェクトにアクセスできなければなりません。アクセス可能
コンポーネントがRoute
に直接リンクされている場合、そのコンポーネントはすでにhistory
オブジェクトにアクセスできます。
例えば:
<Route path="/profile" component={ViewProfile}/>
ここでViewProfile
はhistory
にアクセスできます。
直接Route
に接続されていない場合.
例えば:
<Route path="/users" render={() => <ViewUsers/>}
それから既存のコンポーネントをワープするために、より高次の関数であるwithRouter
を使わなければなりません。
内側 ViewUsers
コンポーネント
import { withRouter } from 'react-router-dom';
export default withRouter(ViewUsers);
これで今、あなたのViewUsers
コンポーネントはhistory
オブジェクトにアクセスできます。
_アップデート_
2
-このシナリオでは、すべてのルートprops
をあなたのコンポーネントに渡してください。そうすればHOC
がなくてもコンポーネントからthis.props.history
にアクセスできます。
例えば:
<Route path="/users" render={props => <ViewUsers {...props} />}
他の人にとって価値がある場合に備えて、もう1つ解決策を提案します。
私はhistory.js
ファイルを持っています。
import createHistory from 'history/createBrowserHistory'
const history = createHistory()
history.pushLater = (...args) => setImmediate(() => history.Push(...args))
export default history
次に、自分のルーターを定義している私のルートでは、次のようにします。
import history from '../history'
import { Provider } from 'react-redux'
import { Router, Route, Switch } from 'react-router-dom'
export default class Root extends React.Component {
render() {
return (
<Provider store={store}>
<Router history={history}>
<Switch>
...
</Switch>
</Router>
</Provider>
)
}
}
最後に、私のactions.js
にHistoryをインポートしてpushLaterを利用します
import history from './history'
export const login = createAction(
...
history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
...)
このようにして、API呼び出し後に新しいアクションにプッシュできます。
それが役に立てば幸い!
ここに私のハックがあります(これは私のルートレベルのファイルで、そこに小さなreduxが混在しています-react-router-redux
は使用していません):
const store = configureStore()
const customHistory = createBrowserHistory({
basename: config.urlBasename || ''
})
ReactDOM.render(
<Provider store={store}>
<Router history={customHistory}>
<Route component={({history}) => {
window.appHistory = history
return (
<App />
)
}}/>
</Router>
</Provider>,
document.getElementById('root')
)
その後、window.appHistory.Push()
を好きな場所(たとえば、reduxストアの関数/サンク/サガなど)で使用できます。ただwindow.customHistory.Push()
を使用できることを望んでいましたが、何らかの理由で、react-router
はURLが変更されても更新されないようでした。しかし、このようにreact-router
が使用するEXACTインスタンスがあります。グローバルな範囲に物を置くのは好きではありませんが、これは私がそれを行う数少ないものの1つです。しかし、それは私がIMOを見た他のどの選択肢よりも優れています。
コールバックを使用してください。それは私のために働いた!
export function addProduct(props, callback) {
return dispatch =>
axios.post(`${ROOT_URL}/cart`, props, config)
.then(response => {
dispatch({ type: types.AUTH_USER });
localStorage.setItem('token', response.data.token);
callback();
});
}
コンポーネントでは、コールバックを追加するだけです
this.props.addProduct(props, () => this.props.history.Push('/cart'))
もしあなたがReduxを使っているなら、npm package react-router-redux を使うことをお勧めします。それはあなたがReduxストアナビゲーションアクションをディスパッチすることを可能にします。
Readmeファイル の説明に従ってstoreを作成する必要があります。
最も簡単なユースケース:
import { Push } from 'react-router-redux'
this.props.dispatch(Push('/second page'));
Container/Componentの2番目のユースケース:
容器:
import { connect } from 'react-redux';
import { Push } from 'react-router-redux';
import Form from '../components/Form';
const mapDispatchToProps = dispatch => ({
changeUrl: url => dispatch(Push(url)),
});
export default connect(null, mapDispatchToProps)(Form);
成分:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class Form extends Component {
handleClick = () => {
this.props.changeUrl('/secondPage');
};
render() {
return (
<div>
<button onClick={this.handleClick}/>
</div>Readme file
);
}
}
私はbind()
を使ってこれを達成することができました。 index.jsx
内のボタンをクリックし、データをサーバーに投稿し、応答を評価し、そしてsuccess.jsx
にリダイレクトしたいと思いました。これが私がどのようにして解決したかです...
index.jsx
:
import React, { Component } from "react"
import { postData } from "../../scripts/request"
class Main extends Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
this.postData = postData.bind(this)
}
handleClick() {
const data = {
"first_name": "Test",
"last_name": "Guy",
"email": "[email protected]"
}
this.postData("person", data)
}
render() {
return (
<div className="Main">
<button onClick={this.handleClick}>Test Post</button>
</div>
)
}
}
export default Main
request.js
:
import { post } from "./fetch"
export const postData = function(url, data) {
// post is a fetch() in another script...
post(url, data)
.then((result) => {
if (result.status === "ok") {
this.props.history.Push("/success")
}
})
}
success.jsx
:
import React from "react"
const Success = () => {
return (
<div className="Success">
Hey cool, got it.
</div>
)
}
export default Success
index.jsx
でthis
をpostData
にバインドすることで、this.props.history
...でrequest.js
にアクセスすることができました。それから私はthis.postData = postData.bind(this)
にconstructor()
を含めることを忘れないでください。
React router V4では、history propを以下のように使うことができます。
this.props.history.Push("/dummy",value)
この値は、ロケーションプロップが使用可能な場合はいつでも、コンポーネント状態ではなく state:{value}
としてアクセスできます。
/*Step 1*/
myFunction(){ this.props.history.Push("/home"); }
/**/
<button onClick={()=>this.myFunction()} className={'btn btn-primary'}>Go
Home</button>
私はログインのためにそれをするようにあなたはそれをこのように使うことができます
class Login extends Component {
constructor(props){
super(props);
this.login=this.login.bind(this)
}
login(){
this.props.history.Push('/dashboard');
}
render() {
return (
<div>
<button onClick={this.login}>login</login>
</div>
)
history.Push
を使用してリダイレクトする代わりに、react-router-dom
からRedirect
コンポーネントを使用するだけです。このコンポーネントを使用するときはPush=true
を渡すことができます。
import * as React from 'react';
import { Redirect } from 'react-router-dom';
class Example extends React.Component {
componentDidMount() {
this.setState({
redirectTo: '/test/path'
});
}
render() {
const { redirectTo } = this.state;
return <Redirect to={{pathname: redirectTo}} Push={true}/>
}
}
ステップ1:アプリをルーターでラップする
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));
これで私のアプリ全体がBrowserRouterにアクセスできるようになります。ステップ2私はRouteをインポートしてからそれらの小道具を渡します。おそらくあなたのメインファイルの1つにあります。
import { Route } from "react-router-dom";
//lots of code here
//somewhere in my render function
<Route
exact
path="/" //put what your file path is here
render={props => (
<div>
<NameOfComponent
{...props} //this will pass down your match, history, location objects
/>
</div>
)}
/>
コンポーネントのjsファイルでconsole.log(this.props)を実行すると、次のようになります。
{match: {…}, location: {…}, history: {…}, //other stuff }
ステップ2履歴オブジェクトにアクセスして自分の位置を変更できます
//lots of code here relating to my whatever request I just ran delete, put so on
this.props.history.Push("/") // then put in whatever url you want to go to
また、私はコーディングブートキャンプの学生なので、私は専門家ではありませんが、あなたも使うことができることを私は知っています
window.location = "/" //wherever you want to go
私が間違っていたら私を訂正しなさい、しかし私がそれをテストしたときそれは私がReactを使うことの全体のポイントを破ったと思ったページ全体をリロードした。
独自のRouter
でカスタムbrowserHistory
を作成します。
import React from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();
const ExtBrowserRouter = ({children}) => (
<Router history={history} >
{ children }
</Router>
);
export default ExtBrowserRouter
次に、Router
を定義するルートで、次を使用します。
import React from 'react';
import { /*BrowserRouter,*/ Route, Switch, Redirect } from 'react-router-dom';
//Use 'ExtBrowserRouter' instead of 'BrowserRouter'
import ExtBrowserRouter from './ExtBrowserRouter';
...
export default class Root extends React.Component {
render() {
return (
<Provider store={store}>
<ExtBrowserRouter>
<Switch>
...
<Route path="/login" component={Login} />
...
</Switch>
</ExtBrowserRouter>
</Provider>
)
}
}
最後に、history
を必要な場所にインポートして使用します。
import { history } from '../routers/ExtBrowserRouter';
...
export function logout(){
clearTokens();
history.Push('/login'); //WORKS AS EXPECTED!
return Promise.reject('Refresh token has expired');
}