从多个源异步更新React状态

时间:2018-04-29 18:44:00

标签: javascript reactjs ecmascript-6 immutability

我尝试使用immutability-helper从多个来源(API调用)异步更新我的React状态。但是,在我看来,这不是可行的方法,因为状态始终只使用来自单个源的值进行更新。有人可以解释一下为什么会这样,以及如何正确处理我的州的更新?

import React from 'react';
import update from 'immutability-helper';

class App extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      updateInterval: 60,  // in seconds
      apiEndpoints: [
        '/stats',
        '/common/stats',
        '/personal/stats',
        '/general_info',
      ],
      items: [
        { itemName: 'One', apiUrl: 'url1', stats: {} },
        { itemName: 'Two', apiUrl: 'url2', stats: {} },
      ],
    };
    this.fetchData = this.fetchData.bind(this);
  }

  componentDidMount() {
    this.fetchData();
    setInterval(() => this.fetchData(), this.state.updateInterval * 1000);
  }

  fetchData() {
    this.state.apiEndpoints.forEach(endpoint => {
      this.state.items.forEach((item, i) => {
        fetch(`${item.apiUrl}${endpoint}`)
          .then(r => r.json())
          .then(res => {
            // response from each endpoint contains different keys.
            // assign all keys to stats object and set default 0 to
            // those which don't exist in response
            const stats = {
              statsFromFirstEndpoint: res.first_endpoint ? res.first_endpoint : 0,
              statsFromSecondEndpoint: res.second_endpoint ? res.second_endpoint : 0,
              statsFromThirdEndpoint: res.third_endpoint ? res.third_endpoint : 0,
            };
            this.setState(update(this.state, {
              items: { [i]: { $merge: { stats } } }
            }));
          })
          .catch(e => { /* log error */ });
      });
    });
  }

  render() {
    return (
      <div className="App">
        Hiya!
      </div>
    );
  }
}

export default App;

1 个答案:

答案 0 :(得分:1)

您应该使用prevState中的setState参数来确保它始终使用最新状态:

this.setState(prevState =>
  update(prevState, {
    items: { [i]: { $merge: { stats } } },
  }));

或者,当所有请求都解决后,将您的请求映射到承诺数组setState

const promises = this.state.apiEndpoints.map(endPoint =>
  Promise.all(this.state.items.map((item, i) =>
    fetch(), // add ur fetch code
  )));
Promise.all(promises).then(res => this.setState( /* update state */ ));