Javascript 从映射函数渲染一系列图像时遇到问题

Javascript 从映射函数渲染一系列图像时遇到问题,javascript,reactjs,rendering,Javascript,Reactjs,Rendering,我正在尝试设计一个组件,用户可以单击一个按钮,该按钮将触发giphy API调用,最终呈现一系列gif图像 到目前为止,我能够成功地完成所有工作,除了实际的图像渲染。以下是我目前的代码: retrieveURLs() { *bunch of stuff to make API call and return an array of URLs related to the category of the button the user pushes* } renderGifs(

我正在尝试设计一个组件,用户可以单击一个按钮,该按钮将触发giphy API调用,最终呈现一系列gif图像

到目前为止,我能够成功地完成所有工作,除了实际的图像渲染。以下是我目前的代码:

retrieveURLs() {
    *bunch of stuff to make API call and return an array of URLs related 
    to the category of the button the user pushes* 
}
renderGifs() {
    this.retrieveURLs().then(function(results) {
        console.log(results); //logs array of URLs  
        return results.map(function(url, index) {
            console.log(url); //logs each url
            return (<img key={index} src={url} alt="" />)
        }, this);   
    });
}
render() {
    return(
        <div id="gif-div">
            {this.renderGifs()}
        </div>
    )
}
retrieveURLs(){
*进行API调用并返回相关URL数组的一堆东西
到用户按下的按钮的类别*
}
renderGifs(){
this.retrieveURLs().then(函数(结果){
console.log(results);//记录URL数组
返回results.map(函数(url、索引){
console.log(url);//记录每个url
返回()
},这个);
});
}
render(){
返回(
{this.renderGifs()}
)
}
尽管每个console.log()事件都指示URL至少被正确传递,但不会呈现任何内容

我对父组件执行了类似的操作,从一组类别中渲染按钮,如下所示:

btnArray = [*bunch of categories here*];
renderButtons() {
    return btnArray.map(function(item, i) {
        let btnID = btnArray[i].replace(/\s+/g, "+");
        return <button type='button' className="btn btn-info" onClick={this.handleCategorySelect} key={i} id={btnID} value={btnID}>{btnArray[i]}</button>
    }, this)
}
btnArray=[*这里有一堆类别*];
renderButtons(){
返回btnArray.map(函数(项,i){
设btnID=btnArray[i]。替换(/\s+/g,“+”);
返回{btnArray[i]}
},本页)
}

按钮已正确渲染,但我的图像未正确渲染。renderbuttons和rendergifs metohds都不会改变状态。老实说,我看不出两者之间有什么有意义的区别,所以我希望能得到一些帮助,弄清楚为什么一个有效,而另一个无效

首先,您忘记了返回语句:

renderGifs() {
    return this.retrieveURLs().then(function(results) {
...
}
但这并不能解决任何问题,因为它返回了一个
承诺

您需要将请求结果保存在状态中,然后将其映射:

constructor(props){
  super(props);

  this.state = { images: [] };
}

componentDidMount() {
   this.renderGifs();
}

renderGifs() {
    this.retrieveURLs().then(function(results) {
        console.log(results); //logs array of URLs  
        this.stateState({ images: results }); 
    });
}

render() {
    return(
        <div id="gif-div">
            {
              this.state.images.map((url, index) => (<img key={index} src={url} alt="" />);
            }
        </div>
    )
}
构造函数(道具){
超级(道具);
this.state={images:[]};
}
componentDidMount(){
这个.renderGifs();
}
renderGifs(){
this.retrieveURLs().then(函数(结果){
console.log(results);//记录URL数组
this.stateState({images:results});
});
}
render(){
返回(
{
this.state.images.map((url,索引)=>();
}
)
}

问题在于图像的渲染功能以及React在上一个和当前状态之间的方式不同。由于提取是异步的,而渲染不是异步的,因此在提取完成时React不知道它需要重新渲染组件。在这种情况下,有一些方法可以强制重新渲染,但更好的方法是解决方案是使用
shouldUpdate
检查中已经包含的功能

您的实现可能会更改为如下所示:

class Images extends Component {
  state = {
    images: [],
    error: null
  }

  componentDidMount() {
    return this.retrieveImages()
      .then(images => this.setState({images}))
      .catch(error => this.setState({error}))
  }

  ... rest of your class definition

  render () {
    return (
      <div>
        {this.state.images.map(image => <img src={image.url} />)}
      </div>
    )
  }
}
类图像扩展组件{
状态={
图像:[],
错误:null
}
componentDidMount(){
返回此。retrieveImages()
.then(images=>this.setState({images}))
.catch(error=>this.setState({error}))
}
…类定义的其余部分
渲染(){
返回(
{this.state.images.map(image=>)}
)
}
}

我也会处理一些不好的结果、缺少键/值等。如果不让我知道,我希望这对您有用!:)

这是异步函数的本质;不能从回调中返回值到原始调用站点。如果你要写:

const res = this.retrieveURLs().then(function(results) {
    return results;
});
您只会更改承诺的分辨率值
res
不会被分配
结果的值,而是被分配由
this.retrieveURLs()
创建的承诺,检索已解析承诺的值的唯一方法是附加
。然后
回调


你能做的是:

this.retrieveURLs().then(results => {
    this.setState({ images: results });  
});
现在,内部状态将异步更新,组件将被告知使用新数据重新渲染,您可以通过访问状态在渲染函数中使用新数据


注意:在上面的示例中,我使用一个arrow函数来创建回调,因为否则
这个
将不会绑定到正确的上下文。或者,您可以执行旧的
即=此
技巧,或者使用
函数#bind

您确定这些
img
标记未在页面中呈现吗?可能url是空的或错误的…是的。没有向应该嵌套图像的div元素内的页面呈现任何内容。是的,即使承诺本身是从
renderGifs
返回的,React也不支持呈现承诺(尽管这很有趣)。完全未经测试,但不知道是否可以执行类似于``async render()的操作{return({await renderImages()}}``而不破坏内容。看起来像是声明
async render(){…}
在React中导致了一个不变的冲突,但这是一个很好的尝试。:-)它确实有帮助,所以谢谢你。你的答案的核心澄清了我需要知道的内容。但是,我不能完全按原样实现你的代码,因为组件呈现时没有主题(retrieveURLs()通过父组件中的
let subject=this.props.category
,定义API调用的主题,该主题在用户按下按钮之前是未定义的,因此componentDidMount将始终返回错误(除非我误解了什么)。因此,如果我理解正确,1)renderButtons()方法之所以工作,是因为它依赖于在呈现组件时已定义的数组(并且独立于状态),但renderGifs()方法不工作,因为它依赖于来自状态(this.state.category)的API调用的结果。2)因此,一旦(category)状态已更改,组件已呈现,承诺对状态(以及组件)没有影响。对吗?
renderButtons
工作,因为它同步地将JSX返回到
render