首页 > 解决方案 > 从返回链接的承诺中获取价值

问题描述

我正在建立一个 ReactJS 网站。
我想通过调用异步函数来访问我的 render() 方法中的链接。我的代码实际上如下:

<a href={this.getDownloadURL(note.noteId)}>
   <span className="downloadAction">
      DOWNLOAD
      <img className="logoImageRight" src={require("../imgs/download.png")} alt="NotFound"/>
   </span>
</a>

我的函数 getDownloadURL() :

async getDownloadURL(noteId){
   var attachmentURL;
   const note = await this.getNote(noteId);
   const {attachment} = note;

   if(attachment){
      attachmentURL = await Storage.vault.get(attachment);
   }
   return(attachmentURL);
} 

目前我的链接类似于http://localhost:3000/[object Promise],这意味着(我认为)我的承诺在我创建链接时还没有完成。有没有人有解决方案如何使我的应答器中的链接正确?

编辑 :

    import React, { Component } from "react";
import { ListGroupItem } from "react-bootstrap";
import { FormGroup, FormControl, ControlLabel, Label } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { API, Storage } from "aws-amplify";
import "./RawList.css";
import { MdMessage } from 'react-icons/md';


export default class RawList extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isLoading: true,
      notes: [],
      inputValue: 0,
      reducedView: true
    };
  }

  async componentDidMount() {

    try {
      const notes = await this.notes();
      this.setState({ notes });
    } catch (e) {
      alert(e);
    }

    this.setState({ isLoading: false });
  }

  notes() {
    return API.get("notes", "/notes");
  }


  getType(attachment){
    if(attachment === undefined){
      return("");
    }
    var tmpString = attachment.split('/')[0];

    if(tmpString === "Oil&GasLease"){
      return("Oil & Gas Lease");
    }
    else if(tmpString === "Oil&GasWell"){
      return("Oil & Gas Well");
    }
    else if(tmpString === "OilMaster"){
      return("Oil Master");
    }
    else if(tmpString === "GasMaster"){
      return("Gas Master");
    }
    else if(tmpString === "OilWellW10"){
      return("Oil Well W10");
    }
    else{
      return("Unknown Type");
    }
  }


  formatFilename(value){
    return(value);
  }

  displayNew(date){
    if(parseInt((Date.now() - date) / 3600000) < 1){
      return(
        <img className="LogoNew" src={require("../imgs/new.png")} alt="NotFound"/>
      );
    }
  }

  getFilename(str){
    return(str.split('\\').pop().split('/').pop().split('-')[1]);
  }

  handleClick(e) {
    this.setState({ reducedView: false });
    e.preventDefault();
  }

  getNote(noteID) {
    return API.get("notes", `/notes/`+noteID);
  }


  async getDownloadURL(noteId){
    var attachmentURL;
    const note = await this.getNote(noteId);
    const {attachment} = note;

    if(attachment){
      attachmentURL = await Storage.vault.get(attachment);
    }
    return(attachmentURL);
  }


  renderNotesList(notes) {
    return [{}].concat(notes).map(
      (note, i) => {
        if(i !== 0){
            if(i >= 6 && notes.length >= 6 && this.state.reducedView){
              if(i === 6){
                return(
                  <ListGroupItem>
                    <img onClick={this.handleClick.bind(this)} src={require("../imgs/3dots.png")} alt="NotFound"/>
                  </ListGroupItem>
                );
              }
            }
            else{
              return(
                <ListGroupItem className="mainContainer">
                  <div className="column1">
                    <img className="Logo" src={require("../imgs/ebc.png")} alt="NotFound"/>
                  </div>
                  <div className="column2">
                    <b>{this.getFilename(note.attachment)}</b>
                    {this.displayNew(note.createdAt)}
                  </div>
                  <div className="column3">
                    {this.humanFileSize(note.input_fileSize)}
                  </div>
                  <div className="column4">
                    {this.getType(note.attachment)}
                  </div>
                  <div className="column5">
                    {new Date(note.createdAt).toLocaleString()}
                  </div>
                  <div className="column6">
                    <a href={'/notes/'+note.noteId}><MdMessage className="commentLogo" size={20}></MdMessage></a>
                  </div>
                  <div className="column7">
                    <span className="convertionAction">
                      CONVERT
                      <img className="logoImageLeft" src={require("../imgs/convertion.png")} alt="NotFound"/>
                    </span>
                  </div>
                  <div className="column8">
                    <a href={this.getDownloadURL(note.noteId)}>
                      <span className="downloadAction">
                        DOWNLOAD
                        <img className="logoImageRight" src={require("../imgs/download.png")} alt="NotFound"/>
                      </span>
                    </a>
                  </div>
                  <div className="column9">
                    <div className="tripleDot"></div>
                  </div>
                </ListGroupItem>
              );
            }
        }
        else{
          if(notes.length === 0){
            return(
              <div>
                <ListGroupItem>
                  <div className="column2Header">
                    File
                  </div>
                  <div className="column3Header">
                    Size
                  </div>
                  <div className="column4Header">
                    Type
                  </div>
                  <div className="column5Header">
                    Date
                  </div>
                  <div className="column6Header">
                    Comment
                  </div>
                </ListGroupItem>
                <LinkContainer key={note.noteId} to={`/upload`}>
                  <ListGroupItem className="upload">
                    <div className="noUpload">
                      + Create new upload
                    </div>
                  </ListGroupItem>
                </LinkContainer>
                <div className="errorMessage">
                  You don't have any existing upload yet.
                </div>
              </div>
              );
          }
          else{
            return(
              <div>
                <ListGroupItem>
                  <div className="column2Header">
                    File
                  </div>
                  <div className="column3Header">
                    Size
                  </div>
                  <div className="column4Header">
                    Type
                  </div>
                  <div className="column5Header">
                    Date
                  </div>
                  <div className="column6Header">
                    Comment
                  </div>
                </ListGroupItem>
                <LinkContainer key={note.noteId} to={`/upload`}>
                  <ListGroupItem className="upload">
                    <div className="noUpload">
                      + Create new upload
                    </div>
                  </ListGroupItem>
                </LinkContainer>
              </div>
            );
          }
        }
      }
    );
  }


  humanFileSize(bytes) {
    var thresh = 1024;
    if(Math.abs(bytes) < thresh) {
        return bytes + ' B';
    }
    var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
    var u = -1;
    do {
        bytes /= thresh;
        ++u;
    } while(Math.abs(bytes) >= thresh && u < units.length - 1);
    return bytes.toFixed(1)+''+units[u];
  }

  handleInputChange = event => {
    var e = document.getElementById("DropdownList");
    var tmp = parseInt(e.options[e.selectedIndex].value);

    if(tmp === 1){
      this.state.notes.sort(function(a,b){
        return this.getType(a.attachment) > this.getType(b.attachment);
      }.bind(this))
    }
    else if(tmp === 2){
      this.state.notes.sort(function(a,b){
        return this.getType(a.attachment) < this.getType(b.attachment);
      }.bind(this))
    }
    else if(tmp === 3){
      this.state.notes.sort(function(a,b){
        return a.attachment < b.attachment;
      })
    }
    else if(tmp === 4){
      this.state.notes.sort(function(a,b){
        return a.attachment > b.attachment;
      })
    }
    else if(tmp === 5){
      this.state.notes.sort(function(a,b){
        return a.fileSize < b.fileSize;
      })
    }
    else if(tmp === 6){
      this.state.notes.sort(function(a,b){
        return a.fileSize > b.fileSize;
      })
    }
    else if(tmp === 7){
      this.state.notes.sort(function(a,b){
        return a.createdAt > b.createdAt;
      })
    }
    else if(tmp === 8){
      this.state.notes.sort(function(a,b){
        return a.createdAt < b.createdAt;
      })
    }

    this.setState({ inputValue: tmp });
  }

  render() {
    return (
      <div className="Supervision">
      <div className="notes">
        <FormGroup onChange={this.handleInputChange}>
          <ControlLabel>Order By :</ControlLabel><br/>
          <select id="DropdownList">
            <option value="0">...</option>
            <option value="1">Type ascending</option>
            <option value="2">Type descending</option>
            <option value="3">Filename ascending</option>
            <option value="4" >Filename descending</option>
            <option value="5">Size ascending</option>
            <option value="6" >Size descending</option>
            <option value="7">Date ascending</option>
            <option value="8">Date descending</option>
          </select>
        </FormGroup>
        {!this.state.isLoading && this.renderNotesList(this.state.notes)}
      </div>
      </div>
    );
  }
}

标签: reactjsasynchronouspromiseasync-awaitcomponents

解决方案


您可以加载下载 URL 并将其置于状态,例如:

function App() {
  const [url, setUrl] = React.useState('')

  React.useEffect(() => {
    getDownloadURL().then(setUrl)
  }, [])

  async function getDownloadURL(){
    return await Promise.resolve('foo')
  }

  return (
    <a href={url}>
      <span className="downloadAction">
        DOWNLOAD
      </span>
    </a>
  );
}

要点是将下载 URL 置入状态,以便您渲染任何处于状态的内容,就像您对 in 所做的notes那样componentDidMount。您可以创建一个DownloadLink组件,如:

class DownloadLink extends React.Component {
  state = { url: "" };

  componentDidMount() {
    const { noteId } = this.props;

    this.getDownloadURL(noteId).then(url => this.setState({ url }));
  }

  getDownloadURL = async function(noteId) {
    // for example
    return await Promise.resolve(`foo/${noteId}`);
  };

  render() {
    return (
      <a href={this.state.url}>
        <span className="downloadAction">DOWNLOAD</span>
      </a>
    );
  }
}

在您的RawList组件中,您可以使用它,而不是:

<div className="column8">
  <a href={this.getDownloadURL(note.noteId)}>
    <span className="downloadAction">
      DOWNLOAD
       <img className="logoImageRight" src={require("../imgs/download.png")} alt="NotFound"/>
      </span>
    </a>
  </div>

使用DownloadLink类似:

<div className="column8">
  <DownloadLink noteId={note.noteId} />
</div>

(如果getDownloadURL在 DownloadLink 中需要更多数据,RawList您可以将其作为道具传递)


推荐阅读