Javascript 使用React呈现json数据时如何执行子查询?

Javascript 使用React呈现json数据时如何执行子查询?,javascript,reactjs,Javascript,Reactjs,编辑:按照@Robin Zigmond的建议,将getMetadata()调用移出渲染。从getMetadata()返回的值中获取正确值仍然有困难,但这与我最初的问题不同。更新代码仅供参考 快速背景:我对shell脚本以及Perl和PHP之类的东西有相当多的经验,但是javascript,尤其是它上面的库React对我来说非常陌生。强迫自己用React来发展这一点,教自己一些新的东西,所以如果你看到任何不好的做法,请随时提出改进建议 也就是说,我正在尝试编写一个简单的应用程序: 提示输入搜索参数

编辑:按照@Robin Zigmond的建议,将getMetadata()调用移出渲染。从getMetadata()返回的值中获取正确值仍然有困难,但这与我最初的问题不同。更新代码仅供参考

快速背景:我对shell脚本以及Perl和PHP之类的东西有相当多的经验,但是javascript,尤其是它上面的库React对我来说非常陌生。强迫自己用React来发展这一点,教自己一些新的东西,所以如果你看到任何不好的做法,请随时提出改进建议

也就是说,我正在尝试编写一个简单的应用程序:

  • 提示输入搜索参数
  • 对返回json结果的第三方服务运行查询
  • 对于每个返回的元素,运行附加查询以获取更多详细信息
  • 显示表格结果
  • 我有1、2和4个基本训练,但3个很难。以下是我到目前为止所做的工作,并删掉了不太重要的代码:

    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 });
            });