[英]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.all
的resolve
回调内移动状态处理代码?
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.