无法使用 react-router 4 以编程方式重定向
Unable to redirect programmatically with react-router 4
我已经阅读了很多关于这个主题的文档和 SOF 问题,我使用了很多方法来做到这一点,但是 none 其中的方法以我需要的方式工作。我想我错过了一些重要的东西。我使用的每一种导航方法都很难提供详细和相关的代码,我会试试的。
这里是一些介绍性的信息。我有 react-redux 应用程序,我需要从服务器获取状态并根据此状态重定向到页面。
我的应用程序的简化版本class渲染方法:
render() {
console.log("App.render");
console.log(this.state);
return (
<div id='game-container' width="1126" height="634">
<Router>
<div>
<Route exact path="/" component={Page1}/>
<Route path="/bets" component={Page2}/>
<Route path="/games" component={Page3}/>
<Route path="/newpage" component={Page4}/>
<Route path="/info" component={ Info }/>
</div>
</Router>
<Overlay/>
</div>
);
}
}
在 index.js 文件
中使用 BrowserRouter 包装的应用程序组件
ReactDOM.render(
<Provider store={myStore}>
<BrowserRouter>
<App assets={ assets } locale={ qs['locale']} token={ qs['token']} sounds={ sounds } />
</BrowserRouter>
</Provider>
, document.querySelector('.game-wrapper'));
方法一.withRouter
为了实现它,我添加了这段代码:
App.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.object.isRequired,
};
function mapStateToProps(state) {
console.log("app#mapStateToProps");
console.log(state.session);
return { session: state.session }
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchInitialSession }, dispatch);
}
export default withRouter(connect(mapStateToProps, { fetchInitialSession })(App));
然后当我获取会话信息时,我尝试:
this.props.history.push("/newpage");
url 在浏览器中正在更改,但可视页面没有。
方法2.使用context router
为此刚刚添加
App.contextTypes = {
router: React.PropTypes.object
};
然后当我获取会话信息时,我尝试:
this.context.router.history.push("/newpage");
与第一种方法相同的结果(url 已更改但页面未更改)。
方法 3. 重定向(在此处找到)
所以我的渲染方法是这样的:
render() {
console.log("App.render");
console.log(this.state);
return (
<div id='game-container' width="1126" height="634">
<Router>
<div>
<Redirect to={{ pathname: this.state.redirectTo }}/>
<Route exact path="/" component={Page1}/>
<Route path="/bets" component={Page2}/>
<Route path="/games" component={Page3}/>
<Route path="/newpage" component={Page4}/>
<Route path="/info" component={ Info }/>
</div>
</Router>
<Overlay/>
</div>
);
}
}
当我想更改页面时,我设置了新状态:
this.setState({ redirectTo: "/newpage" });
这种方法给出了奇怪的结果。当我在构造函数中设置初始状态时,它会重定向到任何页面。但是,当我在代码中的任何地方使用此方法时,我在调试中看到使用我的新状态调用的渲染方法,但重定向从未发生!
在 v4 中,方法 3 应该是正确的方法(使用 Redirect
组件)。您遇到的问题似乎是因为 Redirect
仅在第一次安装时生效,但您将重定向放在路由器的顶层并且它只安装一次。
因此,如果您渲染 <Redirect to={{ pathname: this.state.redirectTo }}/>
,它只会在第一次渲染时重定向,但如果您使用以下方式更新状态,则不会重定向:
this.setState({ redirectTo: "/newpage" });
这就是为什么它仅在您在构造函数中设置 redirectTo
但此后没有再次重定向时才对您有用。
相反,您可能不得不在每个 component/route 中使用 Redirect
来触发重定向,这并不像听起来那么乏味,因为您可以创建自定义路由要使用的组件而不是典型的 Route
组件,并在您的自定义组件中一次处理所有重定向逻辑。
您可以在此处找到一个示例,其中使用 PrivateRoute
和 PublicRoute
而不是正常的 Route
来检查用户是否已登录并相应地重定向:
https://github.com/tylermcginnis/react-router-firebase-auth/blob/master/src/components/index.js
只有登录用户才能访问的 PrivateRoute 如下所示:
function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
我已经阅读了很多关于这个主题的文档和 SOF 问题,我使用了很多方法来做到这一点,但是 none 其中的方法以我需要的方式工作。我想我错过了一些重要的东西。我使用的每一种导航方法都很难提供详细和相关的代码,我会试试的。
这里是一些介绍性的信息。我有 react-redux 应用程序,我需要从服务器获取状态并根据此状态重定向到页面。
我的应用程序的简化版本class渲染方法:
render() {
console.log("App.render");
console.log(this.state);
return (
<div id='game-container' width="1126" height="634">
<Router>
<div>
<Route exact path="/" component={Page1}/>
<Route path="/bets" component={Page2}/>
<Route path="/games" component={Page3}/>
<Route path="/newpage" component={Page4}/>
<Route path="/info" component={ Info }/>
</div>
</Router>
<Overlay/>
</div>
);
}
}
在 index.js 文件
中使用 BrowserRouter 包装的应用程序组件ReactDOM.render(
<Provider store={myStore}>
<BrowserRouter>
<App assets={ assets } locale={ qs['locale']} token={ qs['token']} sounds={ sounds } />
</BrowserRouter>
</Provider>
, document.querySelector('.game-wrapper'));
方法一.withRouter
为了实现它,我添加了这段代码:
App.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.object.isRequired,
};
function mapStateToProps(state) {
console.log("app#mapStateToProps");
console.log(state.session);
return { session: state.session }
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchInitialSession }, dispatch);
}
export default withRouter(connect(mapStateToProps, { fetchInitialSession })(App));
然后当我获取会话信息时,我尝试:
this.props.history.push("/newpage");
url 在浏览器中正在更改,但可视页面没有。
方法2.使用context router
为此刚刚添加
App.contextTypes = {
router: React.PropTypes.object
};
然后当我获取会话信息时,我尝试:
this.context.router.history.push("/newpage");
与第一种方法相同的结果(url 已更改但页面未更改)。
方法 3. 重定向(在此处找到
所以我的渲染方法是这样的:
render() {
console.log("App.render");
console.log(this.state);
return (
<div id='game-container' width="1126" height="634">
<Router>
<div>
<Redirect to={{ pathname: this.state.redirectTo }}/>
<Route exact path="/" component={Page1}/>
<Route path="/bets" component={Page2}/>
<Route path="/games" component={Page3}/>
<Route path="/newpage" component={Page4}/>
<Route path="/info" component={ Info }/>
</div>
</Router>
<Overlay/>
</div>
);
}
}
当我想更改页面时,我设置了新状态:
this.setState({ redirectTo: "/newpage" });
这种方法给出了奇怪的结果。当我在构造函数中设置初始状态时,它会重定向到任何页面。但是,当我在代码中的任何地方使用此方法时,我在调试中看到使用我的新状态调用的渲染方法,但重定向从未发生!
在 v4 中,方法 3 应该是正确的方法(使用 Redirect
组件)。您遇到的问题似乎是因为 Redirect
仅在第一次安装时生效,但您将重定向放在路由器的顶层并且它只安装一次。
因此,如果您渲染 <Redirect to={{ pathname: this.state.redirectTo }}/>
,它只会在第一次渲染时重定向,但如果您使用以下方式更新状态,则不会重定向:
this.setState({ redirectTo: "/newpage" });
这就是为什么它仅在您在构造函数中设置 redirectTo
但此后没有再次重定向时才对您有用。
相反,您可能不得不在每个 component/route 中使用 Redirect
来触发重定向,这并不像听起来那么乏味,因为您可以创建自定义路由要使用的组件而不是典型的 Route
组件,并在您的自定义组件中一次处理所有重定向逻辑。
您可以在此处找到一个示例,其中使用 PrivateRoute
和 PublicRoute
而不是正常的 Route
来检查用户是否已登录并相应地重定向:
https://github.com/tylermcginnis/react-router-firebase-auth/blob/master/src/components/index.js
只有登录用户才能访问的 PrivateRoute 如下所示:
function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}