我正在尝试将状态变量设置为componentWillMount内部的全局变量的值。
我正在基于用户的兴趣进行API调用(使用forEach函数),我试图将结果存储在全局变量中,然后再将其存储在状态变量中(用户:{articles})。
由于某种原因,在渲染中this.state.user.articles
变量始终为空。我想念什么吗?
这是我设置初始值的方式:
class Home extends Component {
constructor(props){
super(props);
this.state = {
user :{
articles: [],
}
}
this.componentWillMount.bind(this);
}
在这里我进行API调用,并尝试使用this.setState
更新varialbe
async componentWillMount(){
const loggedUser = await Auth.currentAuthenticatedUser();
const userEntry = await API.get(apiName,path + loggedUser.username);
console.log(userEntry)
currentInterests = userEntry.userInterests;
currentInterests.forEach(async function (interest) {
console.log(interest);
let query = 'q='+interest+'&';
let url = 'https://newsapi.org/v2/everything?' +
query +
'from=2019-02-22&' +
'sortBy=popularity&' +
'apiKey=hiddenforsecurity';
let req = new Request(url);
const response = await fetch(req);
const json = await response.json();
console.log(typeof json.articles);
for(var key in json.articles){
results.push(json.articles[key])
}
console.log(results[15]);
});
this.setState({
user : {
articles: results,
}
})
}
虽然console.log(results[15])
返回期望的元素,但是在渲染
console.log(this.state.user.articles)
时
render() {
console.log(this.state.user.articles)
return (
<ul>
{this.state.user.articles.map((article, index) => {
console.log(article.author)
return (<li key={index}>{article.author}</li>)})}
</ul>
);
}
返回一个空数组,作为构造函数中的一个数组,表示函数
this.setState({
user : {
articles: results,
}
})
来自componentWillMount的无效。我想念什么?我已经尝试了无数在线修复程序,但似乎没有任何效果。
答案 0 :(得分:1)
主要问题是forEach
不会等待每个回调运行。在下面的示例中,done
将被打印在数组元素(thing1
,thing2
,thing3
)之前。
const things = ["thing1", "thing2", "thing3"];
//https://gist.github.com/eteeselink/81314282c95cd692ea1d
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const exampleFunction = async() => {
things.forEach(async(thing) => {
await delay(500);
console.log(thing);
});
console.log("done");
}
exampleFunction();
在您的示例中,将在实际处理结果之前设置状态。
可以避免这种情况的一种方法是使用for
循环,以便可以await
使用每个语句
const things = ["thing1", "thing2", "thing3"];
//https://gist.github.com/eteeselink/81314282c95cd692ea1d
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const exampleFunction = async() => {
for (let index = 0; index < things.length; index++) {
await delay(500);
console.log(things[index]);
};
console.log("done");
}
exampleFunction();
答案 1 :(得分:1)
setState
在forEach
完成之前被调用,这是一个简单的例子:
const arr = [ 1, 2, 3,4,5];
arr.forEach(async e => {
const a = await fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
console.log(a)
})
console.log('after the loop')
将您的componentWillMount
更新为使用Promise.all
,例如:
async componentWillMount(){
const loggedUser = await Auth.currentAuthenticatedUser();
const userEntry = await API.get(apiName,path + loggedUser.username);
currentInterests = userEntry.userInterests;
const promises = currentInterests.map(interest => {
let query = 'q='+interest+'&';
let url = 'https://newsapi.org/v2/everything?' +
query +
'from=2019-02-22&' +
'sortBy=popularity&' +
'apiKey=hiddenforsecurity';
let req = new Request(url);
return fetch(req);
})
const results = await Promise.all(promises)
.then(res => res.map(e => e.json()))
.then(res => res.map(res.articles));
this.setState({
user : {
articles: results,
}
})
}