存储来自 Axios Promise 的数据以供多种用途

Storing data from Axios Promise for multiple uses

我已经在 express 中创建了一个处理 get 请求的端点。从反应组件中,我使用 axios 向所述端点发出获取请求。我想将数据存储在我的组件 class 中的一个对象中,以便可以多次访问它(onComponentDidLoad、多个 onClick 事件处理程序等)。有没有办法在 axios promise 之外存储数据,and/or 保留 promise 以便我可以执行多个 .then 调用而不履行 promise?

我试过使用 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 调用是可行的。我试的时候格式错了

如果您只是将 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));
}

此代码无法正常工作,因为您试图在不等待数据解析的情况下显示数据:

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

正如您在原始 post 中暗示的那样,您需要从 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>
  }
}