简体   繁体   English

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

[英]How to set state from Multiple API call?

I am having this issue with setState in the code. 我在代码中遇到setState的问题。

Trying to do 尝试做

what I wanted to achieve is to concatenate results from all the API calls into one variable in State.Should I assign everything in the first API (as in second or third API call wrap within the first API .then(function) ?) or should i define each api separately 我想要实现的是将所有API调用的结果连接到State中的一个变量中。我应该在第一个API中分配所有内容(例如在第一个API .then(function)中的第二个或第三个API调用包装中)还是应该我分别定义每个api

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

and call 并打电话

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

What is the right approach? 什么是正确的方法?

ERRORs 错误

No matter the method react logs error. 无论该方法是否反应记录错误。 If I set the State in other API within the first API returns 如果我在第一个API返回的其他API中设置了State

error buzzfeed unidentified 错误buzzfeed无法识别

or setState outside of both API 或两个API之外的setState

error dig , buzzfeed unidentified 错误挖掘,无法识别嗡嗡声

  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); }) } 

thanks for the advice 谢谢你的建议

How about moving state manipulation code within the resolve callback of Promise.all ? 如何在Promise.allresolve回调内移动状态处理代码?

componentDidMount() {
    this.setState({loading: true})
    const apiRequestDig = fetch("api").then(response => response.json());
    const apiRequestNews = fetch("api").then(response => response.json());
    const apiREquestBuzzFeed = fetch("api").then(response => response.json());

    Promise.all([
      apiRequestDig, 
      apiRequestNews, 
      apiREquestBuzzFeed
    ]).then(([dig, news, feed]) => {
      const digs = dig.data.feed.map(article => ({
        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
      }));
      const buzzfeed = feed.big_stories.map(article => ({
        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, ...digs],
        loading: "none"
      });
      // return anything you want as wrapped with promise
      return {
        apiRequestDig: dig,
        apiRequestNews: news,
        apiREquestBuzzFeed: feed
      };
    });
    .catch(e => {
      // catch your error here
    })
}

You could chain your API calls, but Promise.all() allows you to make concurrent calls, so why not use it? 可以链接您的API调用,但是Promise.all()允许您进行并发调用,那么为什么不使用它呢?

However, I think your API functions should be defined outside of componentDidMount , for more readability and reusability: 但是,我认为您的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);
    });
}

Using Promise.all will be the best approach.But keep in mind about the fail fast behavior of Promise.all where in if one request fails then Promise.all will reject immediately MDN Link . 使用Promise.all是最好的方法。但是请注意Promise.all的快速​​故障行为,如果一个请求失败,Promise.all将立即拒绝MDN Link This behavior can be mitigated by catching the error and resolving with empty data. 可以通过捕获错误并解决空白数据来缓解此问题。

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM