首页 > 解决方案 > setState 没有及时更新以更新我的视图

问题描述

我对 React 很陌生,最近从 Angular 迁移过来。我发现使用 setState 更新变量状态的速度不够快,无法反映在我的 render() 中。我想在用户单击按钮后立即显示加载程序,并在关闭按钮后立即隐藏它。但是,当我单击加载图标时,它不会立即显示,并且由于 setState() 的异步行为,显示会略有延迟。是否有任何解决方法。

constructor(props) {
  this.state= {
     displayExportLoading: false
  }
}
download() {
    this.setState({ displayExportLoading: true});

    // async actions of fetching and rendering elements

    // promise is complete

    Promise.all(options)
      .then(() => {
        this.setState({displayExportLoading:false});
      }) 
}
render() {  
      var loadingOnExport = this.state.displayExportLoading? <img src= {loaderExport} width="30px"/>:''

     return(
       <button onClick={this.download}>Download</button>
       <div>
        {loadingOnExport}
       </div>
     ) 
}

我想在单击按钮后立即显示加载程序图像,而不是稍有延迟。这可以在没有状态变量的情况下实现吗?

编辑1:

constructor(props) {
  this.state= {
     displayExportLoading: false
  }
}
download() {
    this.setState({ displayExportLoading: true});
    var pageCount;
    var doc = new jsPDF("p", "mm");
    var pos = 20;
    var gapBetweenImages= 40;
     metrics = metrics.map(async (key, index) => {
      let id_val = `graph-id-${index}`; // creating IDs
      const input = document.getElementById(id_val);
      // html to pdf
      let canvas = await html2canvas(input,[1300,1300]);
      const imgData = canvas.toDataURL("image/JPEG");
      var imgWidth =canvas.width / 8;
      var imgHeight = canvas.height * imgWidth / canvas.width;
      if(index % 2== 0 && index !== 0) {
          pos = 20;
        doc.addPage();
      }
      if( index %2 == 1) {
            pos = imgHeight  + gapBetweenImages;
      }
      doc.addImage(imgData, "JPEG", 15, pos, imgWidth, imgHeight);
    //   doc.addPage();
      console.log("image data",imgData)
      pageCount = doc.internal.getNumberOfPages();
    });
    Promise.all(metrics)
      .then(() => {
        doc.deletePage(pageCount);
        doc.save("file.pdf");
        this.setState({ displayExportLoading: false })

      })
      .catch(err => console.log(err));
    });

}
render() {  
      var loadingOnExport = this.state.displayExportLoading? <img src= {loaderExport} width="30px"/>:''

     return(
       <button onClick={this.download}>Download</button>
       <div>
        {loadingOnExport}
       </div>
     ) 
}

标签: reactjsecmascript-6state

解决方案


通过利用 setState() 回调(第二个参数)尝试以下操作,仅displayExportLoading在设置为true. 从setState()的文档中:

setState() 并不总是立即更新组件。它可能会批量更新或将更新推迟到以后。这使得在调用 setState() 之后立即读取 this.state 是一个潜在的陷阱。相反,使用 componentDidUpdate 或 setState 回调 (setState(updater, callback)),它们都保证在应用更新后触发。如果您需要根据之前的状态设置状态,请阅读下面的 updater 参数。

download() {
    this.setState({ displayExportLoading: true }, () => {
      // async actions of fetching and rendering elements
      // promise is complete

      Promise.all(options)
        .then(() => {
          this.setState({displayExportLoading:false});
        })
      }); 
}

另一种选择可能是使用 CSS可见性来显示/隐藏<img />而不是从 DOM 中添加/删除它:

render() {
     const { displayExportLoading } = this.state;

     return (
       <button onClick={this.download}>Download</button>
       <div style={{ visibility: displayExportLoading ? 'visible' : 'hidden' }}>
         <img src={loaderExport} width="30px" />
       </div>
 );
}

希望这会有所帮助!


推荐阅读