【问题标题】:Having trouble with React rendering a series of images from a map functionReact 从地图函数渲染一系列图像时遇到问题
【发布时间】:2017-09-04 16:14:09
【问题描述】:

我正在尝试设计一个组件,用户可以在其中单击一个按钮,该按钮将触发一个 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>
    )
}

尽管每个 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)
}

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

【问题讨论】:

  • 您确定这些img 标签没有呈现在页面中吗?也许网址为空或错误...
  • 是的。应该嵌套图像的 div 元素内的页面没有呈现任何内容。

标签: javascript reactjs rendering


【解决方案1】:

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

const res = this.retrieveURLs().then(function(results) {
    return results;
});

您只会更改承诺的分辨率值。 res 不会被分配results 的值,而是会被分配由this.retrieveURLs() 创建的promise,并且检索已解决的promise 值的唯一方法是附加一个.then 回调。


你可以这样做:

this.retrieveURLs().then(results => {
    this.setState({ images: results });  
});

现在您的内部状态将异步更新,并且您的组件将被告知使用新数据重新渲染,您可以通过访问状态在渲染函数中使用这些数据。

注意:我在上面的示例中使用箭头函数来创建回调,因为否则this 将不会绑定到正确的上下文。或者,您可以使用旧的that = this 技巧,或使用Function#bind

【讨论】:

  • 所以如果我理解正确的话,1)renderButtons() 方法可以工作,因为它依赖于在渲染组件时已经定义的数组(并且独立于状态),但是renderGifs() 方法不起作用,因为它依赖于来自状态 (this.state.category) 更改的 API 调用的结果。 2)因此,一旦(类别)状态发生变化,组件已经被渲染,并且承诺对状态(以​​及组件)没有影响。对吗?
  • renderButtons 之所以有效,是因为它通过在执行时读取现有数组,将 JSX 同步返回到 render 方法。无需等待某个异步任务完成。 renderGifs() 不起作用 因为它不会立即返回 JSX;它返回 undefined,因此 React 什么也不渲染。所以你别无选择,只能在 promise 的回调中请求 React 重新渲染组件。这样做的方法是使用setState()(除非shouldComponentUpdate 另有说明,否则状态更改会自动导致组件重新渲染)。
  • 看来您可能对这些东西的工作原理有一些误解,所以如果我上面的评论没有完全解决问题,我们可以将其移至聊天。 (哎呀,或者我想我们可以在这里讨论,直到它自动转移到聊天,没有意识到你不能手动做到这一点!)。
【解决方案2】:

问题在于图像的渲染功能以及 React 在先前状态和当前状态之间的差异。由于 fetch 是异步的,而 render 不是,所以当 fetch 完成时,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>
    )
  }
}

我还会对不良结果、缺少键/值等进行一些处理。如果不告诉我,我希望这对你有用! :)

【讨论】:

  • 是的,即使 Promise 本身是从 renderGifs 返回的,React 也不支持渲染 Promise(尽管这会很有趣)。
  • 完全未经测试,但想知道你是否可以在不破坏的情况下执行类似 `` async render() { return (
    {await renderImages()}
    ) } ```东西。
  • 看起来声明 async render() { ... } 会导致 React 中的不变违规,但这是一个不错的尝试。 :-)
  • 确实有帮助,谢谢。您回答的核心阐明了我需要知道的内容。不过,我不能完全按原样实现您的代码,因为该组件是在没有主题的情况下呈现的(retrieveURLs() 定义了let subject = this.props.category 的 API 调用的主题,在用户按下按钮之前它是未定义的)从父组件,所以 componentDidMount 总是会返回一个错误(除非我误解了什么)。
【解决方案3】:

首先你忘记了return语句:

renderGifs() {
    return this.retrieveURLs().then(function(results) {
...
}

但这不会解决任何问题,因为它会返回 Promise

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

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

【讨论】:

    猜你喜欢
    • 2013-04-13
    • 2021-04-08
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多