如何从多个API调用设置状态?

时间:2017-12-03 13:00:47

标签: javascript reactjs

我在代码中遇到了setState的问题。

尝试

我想要实现的是将所有API调用的结果连接到State中的一个变量。我应该在第一个API中分配所有内容(如在第一个API中的第二个或第三个API调用包装。然后(函数)? ) 要么 我应该单独定义每个api

var requestDigAPI = ...
var requestNEWSAPI =...

并致电

    this.setstate({
   this.state.articles.concat(dig,buzzfeed)
})

什么是正确的方法?

错误

无论方法反应日志错误。 如果我在第一个API中的其他API中设置State返回

  

错误buzzfeed unidentified

两个API之外的

或setState

  

错误挖掘,buzzfeed身份不明

    componentDidMount() {
    
        this.setState({loading: true})
    
        var apiRequestDig = fetch("api").then(function(response) {
    
          return response.json()
    
        });
    
        var apiRequestNews = fetch("api").then(function(response) {
    
          return response.json()
    
        })
    
        var apiREquestBuzzFeed = fetch(api).then(function(response) {
    
          return response.json()
    
        })
    
        var combinedData = {
          "apiRequestDig": {},
          "apiRequestNews": {},
          "apiREquestBuzzFeed": {}
        };
    
        Promise.all([apiRequestDig, apiRequestNews, apiREquestBuzzFeed]).then(function(values) {
          combinedData["apiRequestDig"] = values[0];
          combinedData["apiRequestNews"] = values[1];
          combinedData["apiREquestBuzzFeed"] = values[2];
    
    
    
          return combinedData;
        });
    
    
       var dig = apiRequestDig.then(results => {
          let dig = results.data.feed.map(article => {
    
            return {
              title: article.content.title_alt,
              image: article.content.media.images[0].url,
              category: article.content.tags[0].name,
              count: article.digg_score,
              description: article.content.description,
              url: article.content.url
            }
    
          })
          apiREquestBuzzFeed.then(results => {
             console.log(results.big_stories[0].title)
    
             let buzzfeed = results.big_stories.map(article => {
               return {
                 title: article.title,
                 image: article.images.small,
                 category: article.category,
                 count: article.impressions,
                 description: article.description,
                 url: "https://www.buzzfeed.com"+article.canonical_path
               }
             })
           })
    
               this.setState({
                 articles: this.state.articles.concat(dig),
                  loading: "none"
                })
    
    
    
          // console.log(this.state);
        })
    
    
    
      }

感谢您的建议

3 个答案:

答案 0 :(得分:2)

如何在resolve的{​​{1}}回调中移动状态操作代码?

Promise.all

答案 1 :(得分:2)

可以链接您的API调用,但Promise.all()允许您进行并发调用,那么为什么不使用它呢?

但是,我认为您的API函数应该在componentDidMount之外定义,以提高可读性和可重用性:

/* Outside of your component */
const apiRequest = url => fetch(url).then(response => response.json())

const apiRequestDig = () => {
    return apiRequest("https://dig/api/url").then(results => {
        return results.data.feed.map(article => {
            return {
                title: article.content.title_alt
                /* ... */
            };
        });
    });
};

const apiRequestNews = () => {
    return apiRequest("https://news/api/url").then(results => {
        return results.big_stories.map(article => {
            return {
                title: article.title
                /* ... */
            };
        });
    });
};

const apiRequestBuzzFeed = () => {
    return apiRequest("https://buzzfeed/api/url").then(results => {
        return results.big_stories.map(article => {
            return {
                title: article.title
                /* ... */
            };
        });
    });
};

/* Inside your component */
componentDidMount() {
    this.setState({loading: true});

    Promise.all([
        apiRequestDig(),
        apiRequestNews(),
        apiRequestBuzzFeed()
    ]).then(values => {
        return values[0].concat(values[1], values[2]);
    }).then(results => {
        this.setState({
            articles: this.state.articles.concat(results),
            loading: "none"
        });
    }).catch(err => {
        console.log('Oops, something went wrong', err);
    });
}

答案 2 :(得分:0)

使用Promise.all将是最好的方法。但请记住Promise.all的失败快速行为,如果一个请求失败,则Promise.all将立即拒绝MDN Link。通过捕获错误并使用空数据解析可以减轻此行为。

function makeAPICall(postId) {
    return fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`).then(res => res.json());
}

var Posts = React.createClass({
    getInitialState: function() {
        return {};
    },
    componentDidMount: function() {
        var requestsArray = [makeAPICall(1), makeAPICall(2), makeAPICall(3)];
        Promise.all(requestsArray).then(values => {
            var postTitles = values.map(post => post.title).join(",   ");
            this.setState({
                data: postTitles
            });
        }).catch(console.error.bind(console));
    },
    render: function() {
        return <div>{this.state.data}</div>;
    }
});

ReactDOM.render(
    <Posts/>,
    document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>