由于父级重新渲染,ReactJS 计算组件道具更改的状态
ReactJS calculate state on change to components props as a result of parent re-render
我有一个用于学习 ReactJS 的示例应用程序。
它是主从组件的嵌套集。有一个城市列表,您单击一个城市,会显示该城市的一些详细信息以及该城市的公交路线列表。当您单击公交路线时,会显示公交路线的一些(相当可悲 :) 详细信息。
数据都包含在一些数组中,有两个数据辅助函数,但这只是为了简单起见,我会将数据移动到稍后的 AJAX 调用中。
如果您查看 fiddle,您会发现点击城市会正确更新城市详细信息和公交路线列表,点击公交路线会正确显示该公交路线的详细信息。问题是,虽然点击不同的城市确实会更新该城市的公交路线,但它不会显示该城市的第一条公交路线。
这是问题所在: 我认为 CityBusRoutes
组件需要重新计算/更新其状态,但我不知道 how/where 可以这样做。 CityBusRoutes
提供了一个 cityid
然后准备了一个路线列表,我认为应该改变它的状态以将第一条路线存储为所选路线。最初合乎逻辑的地方似乎是在 render 方法中,但这显然是错误的。
请随时提供有关改进设计等的任何建议或文档链接。
谢谢。
代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css"> li{ cursor: pointer; } </style>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/JSXTransformer.js"></script>
<script type="text/jsx">
var cityListing = [
{id: 1, name: 'Rome', desc: 'Capital of Italy'},
{id: 2, name: 'London', desc: 'Capital of UK'},
{id: 3, name: 'Washington', desc: 'Capital of USA'}
];
var cityBuses = [
{
cityid: 1,
routes: [
{id: 707, desc: 'Rome to Beach'},
{id: 717, desc: 'Beach to Rome'},
{id: 708, desc: 'Rome to Naples'},
{id: 718, desc: 'Naples to Rome'}
]
},
{
cityid: 2,
routes: [
{id: 801, desc: 'London to Beach'},
{id: 811, desc: 'Beach to London'},
{id: 802, desc: 'London to Manchester'},
{id: 812, desc: 'Manchester to London'}
]
},
{
cityid: 3,
routes: [
{id: 901, desc: 'Washington to Beach'},
{id: 911, desc: 'Beach to Washington'},
{id: 902, desc: 'Washington to New York'},
{id: 912, desc: 'New York to Washington'}
]
}
];
function findCityBusRoutes(cityid){
for(var i = 0; i < cityBuses.length; i++){
if(cityBuses[i].cityid === cityid) return cityBuses[i];
}
return null;
}
function findBusRouteDetails(routeid){
var c, i, routes;
if(typeof routeid !== 'number') routeid = parseInt(routeid);
for(var c=0; c < cityBuses.length; c++){
routes = cityBuses[c].routes;
for(var i=0; i < routes.length; i++){
if(routes[i].id === routeid){
return "Take a scenic bus trip from " + routes[i].desc + '(' + routes[i].id + ')';
}
}
}
return null;
}
var CityList = React.createClass({
selectCity: function(citylistitem){
this.setState( {selectedCity: citylistitem} );
},
getInitialState: function(){
return {selectedCity: cityListing[0]};
},
render: function(){
var listItems = cityListing.map(function(item){
return <CityListItem key={item.id} data={item} onClick={this.selectCity} />
}, this);
return(
<div>
<ul>{listItems}</ul>
<CityDetail data={this.state.selectedCity} />
</div>
);
}
});
var CityListItem = React.createClass({
clickItem: function(e){
this.props.onClick(this.props.data);
},
render: function(){
return (
<li onClick={this.clickItem}>{this.props.data.name}</li>
)
}
});
var CityDetail = React.createClass({
render: function(){
return(
<div>
<h3>City of {this.props.data.name}</h3>
<p>{this.props.data.desc}</p>
<CityBusRoutes data={this.props.data} />
</div>
);
}
});
var CityBusRoutes = React.createClass({
clickBusRoute: function(e){
this.setState({ routeid: e.currentTarget.getAttribute('data-routeid')});
},
getInitialState: function(){
var cityRoutes = findCityBusRoutes(this.props.data.id);
return {routeid: cityRoutes.routes[0].id};
},
render: function(){
var cityRoutes = findCityBusRoutes(this.props.data.id);
var routeItems = cityRoutes.routes.map(function(route){
return (
<li data-routeid={route.id} onClick={this.clickBusRoute} >Route: {route.id}, Description: {route.desc}</li>
)
}, this);
return(
<div>
<h3>{this.props.data.name} City Bus Routes</h3>
<ul>{routeItems}</ul>
<CityBusRouteDetail routeid={this.state.routeid}/>
</div>
);
}
});
var CityBusRouteDetail = React.createClass({
render: function(){
var rd = findBusRouteDetails(this.props.routeid);
return(
<div>
<h5>Route Details</h5>
<p>{rd}</p>
</div>
);
}
});
React.render(<CityList />, document.getElementById('app'));
</script>
</body>
</html>
好的,所以我找到了答案——将 componentWillReceiveProps()
方法添加到我的 CityBusRoutes
组件正是我要找的。基本上提供了一个地方来计算组件属性更改时的新状态。
componentWillReceiveProps: function(nextProps){
var cityRoutes = findCityBusRoutes(nextProps.data.id);
this.setState({routeid: cityRoutes.routes[0].id});
}
仍然很高兴收到对以上设计的任何评论
componentWillMount & componentWillReceiveProps 是处理这些问题的好方法
我有一个用于学习 ReactJS 的示例应用程序。
它是主从组件的嵌套集。有一个城市列表,您单击一个城市,会显示该城市的一些详细信息以及该城市的公交路线列表。当您单击公交路线时,会显示公交路线的一些(相当可悲 :) 详细信息。
数据都包含在一些数组中,有两个数据辅助函数,但这只是为了简单起见,我会将数据移动到稍后的 AJAX 调用中。
如果您查看 fiddle,您会发现点击城市会正确更新城市详细信息和公交路线列表,点击公交路线会正确显示该公交路线的详细信息。问题是,虽然点击不同的城市确实会更新该城市的公交路线,但它不会显示该城市的第一条公交路线。
这是问题所在: 我认为 CityBusRoutes
组件需要重新计算/更新其状态,但我不知道 how/where 可以这样做。 CityBusRoutes
提供了一个 cityid
然后准备了一个路线列表,我认为应该改变它的状态以将第一条路线存储为所选路线。最初合乎逻辑的地方似乎是在 render 方法中,但这显然是错误的。
请随时提供有关改进设计等的任何建议或文档链接。 谢谢。
代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css"> li{ cursor: pointer; } </style>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/JSXTransformer.js"></script>
<script type="text/jsx">
var cityListing = [
{id: 1, name: 'Rome', desc: 'Capital of Italy'},
{id: 2, name: 'London', desc: 'Capital of UK'},
{id: 3, name: 'Washington', desc: 'Capital of USA'}
];
var cityBuses = [
{
cityid: 1,
routes: [
{id: 707, desc: 'Rome to Beach'},
{id: 717, desc: 'Beach to Rome'},
{id: 708, desc: 'Rome to Naples'},
{id: 718, desc: 'Naples to Rome'}
]
},
{
cityid: 2,
routes: [
{id: 801, desc: 'London to Beach'},
{id: 811, desc: 'Beach to London'},
{id: 802, desc: 'London to Manchester'},
{id: 812, desc: 'Manchester to London'}
]
},
{
cityid: 3,
routes: [
{id: 901, desc: 'Washington to Beach'},
{id: 911, desc: 'Beach to Washington'},
{id: 902, desc: 'Washington to New York'},
{id: 912, desc: 'New York to Washington'}
]
}
];
function findCityBusRoutes(cityid){
for(var i = 0; i < cityBuses.length; i++){
if(cityBuses[i].cityid === cityid) return cityBuses[i];
}
return null;
}
function findBusRouteDetails(routeid){
var c, i, routes;
if(typeof routeid !== 'number') routeid = parseInt(routeid);
for(var c=0; c < cityBuses.length; c++){
routes = cityBuses[c].routes;
for(var i=0; i < routes.length; i++){
if(routes[i].id === routeid){
return "Take a scenic bus trip from " + routes[i].desc + '(' + routes[i].id + ')';
}
}
}
return null;
}
var CityList = React.createClass({
selectCity: function(citylistitem){
this.setState( {selectedCity: citylistitem} );
},
getInitialState: function(){
return {selectedCity: cityListing[0]};
},
render: function(){
var listItems = cityListing.map(function(item){
return <CityListItem key={item.id} data={item} onClick={this.selectCity} />
}, this);
return(
<div>
<ul>{listItems}</ul>
<CityDetail data={this.state.selectedCity} />
</div>
);
}
});
var CityListItem = React.createClass({
clickItem: function(e){
this.props.onClick(this.props.data);
},
render: function(){
return (
<li onClick={this.clickItem}>{this.props.data.name}</li>
)
}
});
var CityDetail = React.createClass({
render: function(){
return(
<div>
<h3>City of {this.props.data.name}</h3>
<p>{this.props.data.desc}</p>
<CityBusRoutes data={this.props.data} />
</div>
);
}
});
var CityBusRoutes = React.createClass({
clickBusRoute: function(e){
this.setState({ routeid: e.currentTarget.getAttribute('data-routeid')});
},
getInitialState: function(){
var cityRoutes = findCityBusRoutes(this.props.data.id);
return {routeid: cityRoutes.routes[0].id};
},
render: function(){
var cityRoutes = findCityBusRoutes(this.props.data.id);
var routeItems = cityRoutes.routes.map(function(route){
return (
<li data-routeid={route.id} onClick={this.clickBusRoute} >Route: {route.id}, Description: {route.desc}</li>
)
}, this);
return(
<div>
<h3>{this.props.data.name} City Bus Routes</h3>
<ul>{routeItems}</ul>
<CityBusRouteDetail routeid={this.state.routeid}/>
</div>
);
}
});
var CityBusRouteDetail = React.createClass({
render: function(){
var rd = findBusRouteDetails(this.props.routeid);
return(
<div>
<h5>Route Details</h5>
<p>{rd}</p>
</div>
);
}
});
React.render(<CityList />, document.getElementById('app'));
</script>
</body>
</html>
好的,所以我找到了答案——将 componentWillReceiveProps()
方法添加到我的 CityBusRoutes
组件正是我要找的。基本上提供了一个地方来计算组件属性更改时的新状态。
componentWillReceiveProps: function(nextProps){
var cityRoutes = findCityBusRoutes(nextProps.data.id);
this.setState({routeid: cityRoutes.routes[0].id});
}
仍然很高兴收到对以上设计的任何评论
componentWillMount & componentWillReceiveProps 是处理这些问题的好方法