Javascript 使用React呈现json数据时如何执行子查询?
编辑:按照@Robin Zigmond的建议,将getMetadata()调用移出渲染。从getMetadata()返回的值中获取正确值仍然有困难,但这与我最初的问题不同。更新代码仅供参考 快速背景:我对shell脚本以及Perl和PHP之类的东西有相当多的经验,但是javascript,尤其是它上面的库React对我来说非常陌生。强迫自己用React来发展这一点,教自己一些新的东西,所以如果你看到任何不好的做法,请随时提出改进建议 也就是说,我正在尝试编写一个简单的应用程序:Javascript 使用React呈现json数据时如何执行子查询?,javascript,reactjs,Javascript,Reactjs,编辑:按照@Robin Zigmond的建议,将getMetadata()调用移出渲染。从getMetadata()返回的值中获取正确值仍然有困难,但这与我最初的问题不同。更新代码仅供参考 快速背景:我对shell脚本以及Perl和PHP之类的东西有相当多的经验,但是javascript,尤其是它上面的库React对我来说非常陌生。强迫自己用React来发展这一点,教自己一些新的东西,所以如果你看到任何不好的做法,请随时提出改进建议 也就是说,我正在尝试编写一个简单的应用程序: 提示输入搜索参数
class VGSC_Search extends React.Component {
constructor() {
super();
this.state = {
submitted: false,
platform: '',
games: [],
metadata: [],
files: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({platform: event.target.value});
}
handleSubmit(event) {
this.setState({submitted: true});
<SNIP - vars>
fetch(encodeURI(searchurl + query + fields + sort + rows))
.then(result => result.json())
.then(data => this.setState({
games: data.response.docs.map(game => ({
identifier: game.identifier,
title: game.title,
creator: game.creator,
year: game.year,
uploader: this.getMetadata(game.identifier),
}))
}));
event.preventDefault();
}
getMetadata(id) {
<SNIP - vars>
fetch(encodeURI(metadataurl + id + metadatainfo))
.then(result => result.json())
.then(data => this.setState({metadata: data.response}));
}
renderResults() {
const {games} = this.state;
const {metadata} = this.state;
return (
<SNIP - table header>
<tbody>{games.map(game =>
<tr key={game.identifier}>
<td><a href={'https://archive.org/details/' + game.identifier}>{game.title}</a></td>
<td>{game.creator}</td>
<td>{game.year}</td>
<td>{game.uploader}</td>
</tr>
)}</tbody>
</table>
);
}
render(){
return (
<div>
<SNIP - form>
<br/>
{this.state.submitted && this.renderResults()}
</div>
);
}
}
classvgsc\u搜索扩展了React.Component{
构造函数(){
超级();
此.state={
提交:假,
平台:“”,
游戏:[],
元数据:[],
文件:[],
};
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
手变(活动){
this.setState({platform:event.target.value});
}
handleSubmit(事件){
this.setState({submitted:true});
获取(encodeURI(搜索URL+查询+字段+排序+行))
.then(result=>result.json())
.然后(数据=>this.setState({
游戏:data.response.docs.map(游戏=>({
标识符:game.identifier,
标题:游戏,标题,
创造者:游戏创造者,
年份:game.year,
uploader:this.getMetadata(game.identifier),
}))
}));
event.preventDefault();
}
getMetadata(id){
获取(encodeURI(metadataurl+id+metadatainfo))
.then(result=>result.json())
.then(data=>this.setState({metadata:data.response}));
}
renderResults(){
const{games}=this.state;
const{metadata}=this.state;
返回(
{games.map(game=>
{game.creator}
{game.year}
{game.uploader}
)}
);
}
render(){
返回(
{this.state.submitted&&this.renderResults()}
);
}
}
我的问题是Uploader字段,它应该在给定的标识符上运行getMetadata(),并返回Uploader的名称。我很难弄清楚如何引用结果,但我最大的问题是,我的浏览器一直在无休止的循环中对所有显示的项目运行getMetadata()。例如,从开发者工具日志:
XHR GET https://archive.org/metadata/4WheelThunderEuropePromoDiscLabel/metadata/uploader [HTTP/1.1 200 OK 105ms]
XHR GET https://archive.org/metadata/AirJapanCompleteArtScans/metadata/uploader [HTTP/1.1 200 OK 279ms]
XHR GET https://archive.org/metadata/AeroWings-CompleteScans/metadata/uploader [HTTP/1.1 200 OK 287ms]
XHR GET https://archive.org/metadata/BioCodeVeronicaLEDCT1210MNTSCJ/metadata/uploader [HTTP/1.1 200 OK 279ms]
XHR GET https://archive.org/metadata/Biohazard2ValuePlusDreamcastT1214MNTSCJ/metadata/uploader [HTTP/1.1 200 OK 282ms]
XHR GET https://archive.org/metadata/4WheelThunderEuropePromoDiscLabel/metadata/uploader [HTTP/1.1 200 OK 120ms]
XHR GET https://archive.org/metadata/AirJapanCompleteArtScans/metadata/uploader [HTTP/1.1 200 OK 120ms]
<SNIP>
XHR-GEThttps://archive.org/metadata/4WheelThunderEuropePromoDiscLabel/metadata/uploader [HTTP/1.1 200 OK 105ms]
XHR GEThttps://archive.org/metadata/AirJapanCompleteArtScans/metadata/uploader [HTTP/1.1 200 OK 279毫秒]
XHR GEThttps://archive.org/metadata/AeroWings-CompleteScans/metadata/uploader [HTTP/1.1 200 OK 287ms]
XHR GEThttps://archive.org/metadata/BioCodeVeronicaLEDCT1210MNTSCJ/metadata/uploader [HTTP/1.1 200 OK 279毫秒]
XHR GEThttps://archive.org/metadata/Biohazard2ValuePlusDreamcastT1214MNTSCJ/metadata/uploader [HTTP/1.1 200 OK 282ms]
XHR GEThttps://archive.org/metadata/4WheelThunderEuropePromoDiscLabel/metadata/uploader [HTTP/1.1 200 OK 120ms]
XHR GEThttps://archive.org/metadata/AirJapanCompleteArtScans/metadata/uploader [HTTP/1.1 200 OK 120ms]
第一次搜索返回5个结果,getMetadata()在这5个结果上正确运行,但请注意,它开始重复。它会一直这样做直到我重新加载页面
我猜这与在呈现的函数中运行getMetadata()有关,但我不确定原因,并且很难想出一种好的替代方法
有谁能解释一下我为什么会看到这种行为,并(希望)就如何正确实施这一点提出建议吗
谢谢 无限循环之所以发生,是因为您在
render
内部运行getMetadata
(或者更确切地说是在从render
调用的函数内部运行),这会导致状态更改,从而导致重新渲染,等等
在任何情况下,从render
-render
调用任何函数都会导致任何“副作用”,这是一种不好的做法,只要根据组件的道具和状态确定输出即可。通常,像您这样的数据获取是在componentDidMount
和/或componentdiddupdate
内部完成的。但是,在这种情况下,如果您似乎需要根据handleSubmit
中的第一个响应获取其他数据,那么您似乎需要从最终的中调用getMetadata
。然后调用该函数的回调
在您最近的编辑之后,我可以看到您在这里尝试的方法的问题this.getMetadata实际上不返回任何内容。要修复它,您可以返回通过获取返回的承诺
:
getMetadata(id) {
<SNIP - vars>
return fetch(encodeURI(metadataurl + id + metadatainfo))
.then(result => result.json())
.then(data => this.setState({metadata: data.response}));
}
这是因为您在render
内部运行getMetadata
(或者更确切地说是在从render
调用的函数内部运行),这会导致状态更改,从而导致重新渲染,等等,这是一个无休止的循环。从re中调用任何会导致任何“副作用”的函数都是不好的做法
fetch(encodeURI(searchurl + query + fields + sort + rows))
.then(result => result.json())
.then(async data => {
const games = await Promise.all(data.response.docs.map(async game => ({
identifier: game.identifier,
title: game.title,
creator: game.creator,
year: game.year,
uploader: await this.getMetadata(game.identifier),
})));
this.setState({ games });
});