【问题标题】:Storing data from Axios Promise for multiple uses从 Axios Promise 存储数据以供多种用途
【发布时间】:2021-12-11 05:48:22
【问题描述】:

我在 express 中创建了一个处理 get 请求的端点。从一个反应组件,我使用 axios 向所述端点发出一个 get 请求。我想将数据存储在我的 Component 类中的一个对象中,以便可以多次访问它(onComponentDidLoad、多个 onClick 事件处理程序等)。有没有办法将数据存储在 axios 承诺之外,和/或保留承诺,以便我可以在不履行承诺的情况下进行多次 .then 调用?

我尝试过使用 setState(),返回 promise,并从 get 请求中返回实际数据。

这是我现在拥有的:

constructor {
  super();
  this.myData = [];
  
  this.getData = this.getData.bind(this);
  this.storeData = this.storeData.bind(this);
  this.showData = this.showData.bind(this);
}

// Store data
storeData = (data) => {this.myData.push(data)};

// Get data from API
getData() {
    axios
        .get('/someEndpoint')
        .then(response => {
            let body = response['data'];

            if(body) {
                this.storeData(body);
            }
        })
        .catch(function(error) {
            console.log(error);
        });
}

showData() {
    console.log(this.myData.length); // Always results in '0'
}

componentDidMount = () => {
    this.getData();   // Get data
    this.showData();   // Show Data
}
    
render() {
  return(
      <Button onClick={this.showData}> Show Data </Button>
  );
}

编辑 我的问题是不正确的,存储承诺然后进行多个 .then 调用有效。我试过的时候格式不对。

【问题讨论】:

  • "保留承诺,以便我可以进行多次 .then 调用" - 是的,就这样做
  • @Bergi 只能使用一次。在一个 .then 调用promise之后,数据就不能再访问了。
  • 没有。您可以根据同一承诺多次致电.then()。一旦实现了承诺,就会调用回调。一个已实现的承诺确实会永远保持它的价值,它不会以某种方式“失去它”。
  • 哦,你不会撒谎@Bergi

标签: javascript reactjs promise axios


【解决方案1】:

此代码无法正常工作,因为您正在尝试显示数据而不等待解析:

componentDidMount = () => {
    this.getData();
    this.showData();
}

正如您在原始帖子中所暗示的那样,您需要从 Promise 中提取数据,并且无法以同步方式执行此操作。您可以做的第一件事就是简单地存储原始 Promise 并在需要时访问它 - Promise 可以then()ed 多次:

class C extends React.Component {
  state = {
    promise: Promise.reject("not yet ready")
  };

  showData = async () => {
    // You can now re-use this.state.promise.
    // The caveat here is that you might potentially wait forever for a promise to resolve.
    console.log(await this.state.promise);
  }

  componentDidMount() {
    const t = fetchData();
    this.setState({ promise: t });
    // Take care not to re-assign here this.state.promise here, as otherwise
    // subsequent calls to t.then() will have the return value of showData() (undefined)
    // instead of the data you want.
    t.then(() => this.showData());
  }
  
  render() {
    const handleClick = () => {
      this.showData();
    };

    return <button onClick={handleClick}>Click Me</button>;
  }
}

另一种方法是尝试通过将异步完全限制为 fetchData() 函数来尽可能保持组件同步,这可能会使您的组件更容易推理:

class C extends React.Component {
  state = {
    status: "pending",
    data: undefined
  };

  async fetchData(abortSignal) {
    this.setState({ status: "pending" });
    try {
      const response = await fetch(..., { signal: abortSignal });
      const data = await response.json();
      this.setState({ data: data, status: "ok" });
    } catch (err) {
      this.setState({ error: err, status: "error" });
    } finally {
      this.setState({ status: "pending" });
    }
  }

  showData() {
    // Note how we now do not need to pollute showData() with asyncrony
    switch (this.state.status) {
      case "pending":
        ...
      case "ok":
        console.log(this.state.data);
      case "error":
        ...
    }
  }

  componentDidMount() {
    // Using an instance property is analogous to using a ref in React Hooks.
    // We don't want this to be state because we don't want the component to update when the abort controller changes.
    this.abortCtrl = new AbortController();
    this.fetchData(this.abortCtrl.signal);
  }

  componentDidUnmount() {
    this.abortCtrl.abort();
  }

  render() {
    return <button onClick={() => this.showData()}>Click Me</button>
  }
}

【讨论】:

    【解决方案2】:

    如果您只是将 Promise 存储在本地并作为 Promise 访问它应该可以正常工作。

    getData() {
      // if request has already been made then just return the previous request.
      this.data = this.data || axios.get(url)
      .then( response => response.data)
      .catch(console.log)
      return this.data
    }
    
    showData() {
      this.getData().then(d => console.log('my data is', data));
    }
    

    【讨论】:

    • 这在第一次调用 showData() 时有效,但如果我尝试多次调用 showData,则承诺“履行”并且结果为空。
    • 如果 Promise 在任何时候出错都会中断,但只要 axios 使用符合 Promise 的规范并且您删除了 catch() 分支,它应该可以工作。也就是说,除非您不希望组件在实例属性更改时更新,否则不应像这样分配实例属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 2019-03-14
    • 1970-01-01
    • 2019-04-22
    • 2018-07-03
    • 2012-04-18
    • 2021-09-25
    相关资源
    最近更新 更多