我正在使用React Router。在我的州,我有一些可通过身份识别识别的电视节目。在节目页面上,我需要加载特定节目的数据,将节目ID与URL的末尾相匹配。
我的州看起来像这样,但有更多的节目:
shows: [
{
id: 1318913
name: "Countdown"
time: "14:10"
},
{
id: 1318914
name: "The News"
time: "15:00"
}
]
在App.js中:
<BrowserRouter>
<Switch>
<Route
exact
path="/"
render={() => {
return <Table shows={this.state.shows} />;
}}
/>
<Route
path="/show/:showID"
render={() => {
return <Show />;
}}
/>
<Route component={FourOhFour} />
</Switch>
</BrowserRouter>;
React Router在显示页面上显示URL的showID部分。所以我可以将我的整个show状态传递给Show组件,然后从url中找到正确的show。但是我想这个效率低下?
我想知道我是否应该通过App.js中的ID查看节目,并且只将正确的节目传递给Show组件。这是更好的做法/更有效吗?
这是我的表组件:
class Table extends Component {
render(props) {
return (
<table className="table table-striped table-bordered table-hover">
<tbody>
{
this.props.shows.map((item)=>{
return <TableRow
name={item.name}
time={item.time}
key={item.eppisodeId}
eppisodeId={item.eppisodeId}
img={item.img}
/>
})
}
</tbody>
</table>
)
}
}
这是我的TableRow组件:
class TableRow extends Component {
render(props) {
const image = this.props.img !== null ?
<img src={this.props.img} alt={this.props.name} />
: null;
const showUrl = '/show/' + this.props.eppisodeId;
return (
<tr className="tableRow">
<td className="tableRow--imgTd">{image}</td>
<td><Link to={showUrl}>{this.props.name}</Link></td>
<td className="tableRow--timeTd">{this.props.time}</td>
</tr>
)
}
}
答案 0 :(得分:2)
正如我在您的问题中所看到的,您正在使用Link
进行导航。考虑到您还希望通过链接发送数据,您可以将对象传递给它而不是React-router docs中提到的string path
,因此您可以使用{{1}传递节目信息在state object
组件中
TableRow
现在,您可以在const {name, time, episodeId, img} = this.props;
<Link to={{pathname:showUrl, state: {show: {name, time, episodeId, img }}}}>{this.props.name}</Link>
组件中检索此信息
Show
您需要注意的另一件事是,您需要将道具传递给渲染函数
this.props.location.state && this.props.location.state.name
现在上述解决方案仅在您从App中导航时才有效,但是如果您更改URL将无效,如果您想使其更加健壮,您需要将数据传递给show组件然后优化生命周期功能
你愿意。这样做
<Switch>
<Route
exact
path="/"
render={(props) => {
return <Table shows={this.state.shows} {...props}/>;
}}
/>
<Route
path="/show/:showID"
render={(props) => {
return <Show {...props}/>;
}}
/>
<Route component={FourOhFour} />
</Switch>
然后在Show组件
中<Switch>
<Route
exact
path="/"
render={(props) => {
return <Table shows={this.state.shows} {...props}/>;
}}
/>
<Route
path="/show/:showID"
render={(props) => {
return <Show shows={this.state.shows} {...props}/>;
}}
/>
<Route component={FourOhFour} />
</Switch>
然而,这就是像redux
和reselect
这样的图书馆有用的地方。使用Redux,您的数据class Show extends React.Component {
componentDidMount() {
const {shows, match} = this.props;
const {params} = match;
// get the data from shows which matches params.id here using `find` or `filter` or whatever you feel appropriate
}
componentWillReceiveProps(nextProps) {
const {match} = this.props;
const {shows: nextShows, match: nextMatch} = nextProps;
const {params} = match;
const {params: nextParams} = nextMatch;
if( nextParams.showId !== params.showId) {
// get the data from nextProps.showId and nextShows here
}
}
}
将位于一个公共存储中,您可以在任何组件中访问它,shows
为您提供了一个选项,可以创建一个备忘的选择器以获取相应的reselect
数据来自show
,因此不再重复相同的计算。请探讨这些并检查它们是否适合您的项目。
答案 1 :(得分:0)
组件参数可以接受一个功能。如果您使用props.match.params.id
传递道具,则可以从网址中找到ID。当我们处于一个函数中时,我们能够从我们的状态中找到该节目并将其传递给Show组件。
<BrowserRouter>
<Switch>
<Route
exact
path="/"
render={() => {
return <Table shows={this.state.shows} />;
}}
/>
<Route path="/show/:id" component={(props)=>{
const foundShow = this.state.shows.find((show)=>{
const urlId = props.match.params.id;
return show.eppisodeId === parseInt(urlId);
});
// {...props} is optional, it will pass the other properties from React Router
return <Show show={foundShow} {...props} />
}} />
<Route component={FourOhFour} />
</Switch>
</BrowserRouter>;
然而,有一些奇怪的行为。如果我在Show组件中console.log(this.props);
,那么我可以看到它被渲染两次。第一次this.props.show
为空,第二次有我传递的数据。这是一个真正的痛苦,因为我必须在渲染之前检查每个变量的存在,这使得我必须做错事......
更新:以下解决了上述问题,但我不知道这是不是一个好习惯:
class Show extends Component {
render(props) {
if (this.props.foundShow) {
const {name, network, time} = this.props.foundShow;
return (
<div>
<h2>
{name} on {network} at {time}
</h2>
</div>
)
} else {
return (
<h2>Loading....</h2>
)
}
}
}