如何使用 react-router 导航嵌套组件 4
How to navigate nested components with react-router 4
我有一个带有按钮、通用背景和通用标题以及不断变化的嵌套组件的屏幕。在此屏幕内,我想通过单击按钮来更改嵌套组件。嵌套的组件必须用左右按钮在一个圆圈内相互改变。到目前为止,我做了很多尝试来实现这一点(我尝试使用 withRouter 来做到这一点),我只给你我的一次尝试的代码,但所有这些都没有用。我没有收到任何错误,我看到浏览器中的路由正在更改但屏幕没有,我只看到第一个嵌套组件。 SOF 上有关于此的问题,但它们与 react-router 的旧版本有关。
这是我的代码,如果您需要更多信息,请随时在评论中提问。
import React, { Component } from 'react';
import { Link,
BrowserRouter as Router,
Route,
Switch,
withRouter } from 'react-router-dom';
import Info1 from './info/info1';
import Info2 from './info/info2';
import Info3 from './info/info3';
import Info4 from './info/info4';
class Info extends Component {
constructor(props) {
super(props);
this.currentIndex = 1;
}
componentDidMount() {
}
leftHandler() {
console.log("left click");
var temp = this.currentIndex;
this.changeScreen(--temp);
}
rightHandler() {
console.log("right click");
var temp = this.currentIndex;
this.changeScreen(++temp);
}
changeScreen(index) {
const numberOfScreens = 4;
if(index < 1)
this.currentIndex = numberOfScreens;
else if(index > numberOfScreens)
this.currentIndex = 1;
else
this.currentIndex = index;
this.props.history.push("/info/" + this.currentIndex);
}
render() {
return (
<Router>
<div className="info-common">
<img className="game-title info-game"/>
<Switch>
<Route path="/info/1" component={ Info1 }/>
<Route path="/info/2" component={ Info2 }/>
<Route path="/info/3" component={ Info3 }/>
<Route path="/info/4" component={ Info4 }/>
</Switch>
<Link to="/rings"><button className="back-info-btn">назад</button></Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
</Router>
);
}
}
Info.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.isRequired,
};
export default withRouter(Info);
编辑:
虽然我接受了给出的答案,但我没有测试它,在我的项目中我使用了这个解决方案:
app.js
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
...
render() {
return (
<div id='game-container' width="1236" height="634">
<Router>
<div>
<Route path="/info" component={ Info }/>
</div>
</Router>
</div>
);
}
然后在 Info 本身:
Info.js
class Info extends Component {
constructor(props) {
super(props);
this.currentIndex = 1;
}
leftHandler() {
console.log("left click");
var temp = this.currentIndex;
this.changeScreen(--temp);
}
rightHandler() {
console.log("right click");
var temp = this.currentIndex;
this.changeScreen(++temp);
}
changeScreen(index) {
const numberOfScreens = 4;
if(index < 1)
this.currentIndex = numberOfScreens;
else if(index > numberOfScreens)
this.currentIndex = 1;
else
this.currentIndex = index;
this.props.history.push("/info/" + this.currentIndex);
}
render() {
return (
<div className="info-common">
<img className="game-title info-game" src={ this.drawGame() }/>
<Switch>
<Route path={`${this.props.match.path}/1`} component={ Info1 }/>
<Route path={`${this.props.match.path}/2`} component={ Info2 }/>
<Route path={`${this.props.match.path}/3`} component={ Info3 }/>
<Route path={`${this.props.match.path}/4`} component={ Info4 }/>
</Switch>
<Link to="/rings"><button className="back-info-btn">назад</button></Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
);
}
}
Info.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.object.isRequired,
};
export default withRouter(Info);
如果你将组件包裹在 withRouter
中,你只能在 <Router>
中使用它,就像 <Route>
s 等
为了使您的示例正常运行,您需要使 <Info>
成为 <Router>
的子级,因为它使用 withRouter
。首先,从 render
方法中删除 <Router>
,只将 <div>
渲染为顶级组件:
render() {
return (
<div className="info-common">
<img className="game-title info-game"/>
<Switch>
<Route path="/info/1" component={ Info1 }/>
<Route path="/info/2" component={ Info2 }/>
<Route path="/info/3" component={ Info3 }/>
<Route path="/info/4" component={ Info4 }/>
</Switch>
<Link to="/rings">
<button className="back-info-btn">назад</button>
</Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
)
}
然后,无论您在哪里渲染 <Info />
,都渲染 <Router><Info /></Router>
。或者,添加一个额外的组件来呈现这两个组件,并使用该组件代替 <Info />
.
// Option 1: render <Router> wherever you use <Info>
import Info from './info';
...
ReactDOM.render(<Router><Info /></Router>);
// Option 2: add another component that wraps <Info> in a Router,
// either as the new export of the module, or as a new module
const App = () => (
<Router>
<Info />
</Router>
);
export default App;
我有一个带有按钮、通用背景和通用标题以及不断变化的嵌套组件的屏幕。在此屏幕内,我想通过单击按钮来更改嵌套组件。嵌套的组件必须用左右按钮在一个圆圈内相互改变。到目前为止,我做了很多尝试来实现这一点(我尝试使用 withRouter 来做到这一点),我只给你我的一次尝试的代码,但所有这些都没有用。我没有收到任何错误,我看到浏览器中的路由正在更改但屏幕没有,我只看到第一个嵌套组件。 SOF 上有关于此的问题,但它们与 react-router 的旧版本有关。 这是我的代码,如果您需要更多信息,请随时在评论中提问。
import React, { Component } from 'react';
import { Link,
BrowserRouter as Router,
Route,
Switch,
withRouter } from 'react-router-dom';
import Info1 from './info/info1';
import Info2 from './info/info2';
import Info3 from './info/info3';
import Info4 from './info/info4';
class Info extends Component {
constructor(props) {
super(props);
this.currentIndex = 1;
}
componentDidMount() {
}
leftHandler() {
console.log("left click");
var temp = this.currentIndex;
this.changeScreen(--temp);
}
rightHandler() {
console.log("right click");
var temp = this.currentIndex;
this.changeScreen(++temp);
}
changeScreen(index) {
const numberOfScreens = 4;
if(index < 1)
this.currentIndex = numberOfScreens;
else if(index > numberOfScreens)
this.currentIndex = 1;
else
this.currentIndex = index;
this.props.history.push("/info/" + this.currentIndex);
}
render() {
return (
<Router>
<div className="info-common">
<img className="game-title info-game"/>
<Switch>
<Route path="/info/1" component={ Info1 }/>
<Route path="/info/2" component={ Info2 }/>
<Route path="/info/3" component={ Info3 }/>
<Route path="/info/4" component={ Info4 }/>
</Switch>
<Link to="/rings"><button className="back-info-btn">назад</button></Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
</Router>
);
}
}
Info.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.isRequired,
};
export default withRouter(Info);
编辑: 虽然我接受了给出的答案,但我没有测试它,在我的项目中我使用了这个解决方案:
app.js
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
...
render() {
return (
<div id='game-container' width="1236" height="634">
<Router>
<div>
<Route path="/info" component={ Info }/>
</div>
</Router>
</div>
);
}
然后在 Info 本身:
Info.js
class Info extends Component {
constructor(props) {
super(props);
this.currentIndex = 1;
}
leftHandler() {
console.log("left click");
var temp = this.currentIndex;
this.changeScreen(--temp);
}
rightHandler() {
console.log("right click");
var temp = this.currentIndex;
this.changeScreen(++temp);
}
changeScreen(index) {
const numberOfScreens = 4;
if(index < 1)
this.currentIndex = numberOfScreens;
else if(index > numberOfScreens)
this.currentIndex = 1;
else
this.currentIndex = index;
this.props.history.push("/info/" + this.currentIndex);
}
render() {
return (
<div className="info-common">
<img className="game-title info-game" src={ this.drawGame() }/>
<Switch>
<Route path={`${this.props.match.path}/1`} component={ Info1 }/>
<Route path={`${this.props.match.path}/2`} component={ Info2 }/>
<Route path={`${this.props.match.path}/3`} component={ Info3 }/>
<Route path={`${this.props.match.path}/4`} component={ Info4 }/>
</Switch>
<Link to="/rings"><button className="back-info-btn">назад</button></Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
);
}
}
Info.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}).isRequired,
location: React.PropTypes.object.isRequired,
};
export default withRouter(Info);
如果你将组件包裹在 withRouter
中,你只能在 <Router>
中使用它,就像 <Route>
s 等
为了使您的示例正常运行,您需要使 <Info>
成为 <Router>
的子级,因为它使用 withRouter
。首先,从 render
方法中删除 <Router>
,只将 <div>
渲染为顶级组件:
render() {
return (
<div className="info-common">
<img className="game-title info-game"/>
<Switch>
<Route path="/info/1" component={ Info1 }/>
<Route path="/info/2" component={ Info2 }/>
<Route path="/info/3" component={ Info3 }/>
<Route path="/info/4" component={ Info4 }/>
</Switch>
<Link to="/rings">
<button className="back-info-btn">назад</button>
</Link>
<button onClick={ this.leftHandler.bind(this) } className="left-info-btn"></button>
<button onClick={ this.rightHandler.bind(this)} className="right-info-btn"></button>
</div>
)
}
然后,无论您在哪里渲染 <Info />
,都渲染 <Router><Info /></Router>
。或者,添加一个额外的组件来呈现这两个组件,并使用该组件代替 <Info />
.
// Option 1: render <Router> wherever you use <Info>
import Info from './info';
...
ReactDOM.render(<Router><Info /></Router>);
// Option 2: add another component that wraps <Info> in a Router,
// either as the new export of the module, or as a new module
const App = () => (
<Router>
<Info />
</Router>
);
export default App;