如何在React中从全局变量设置状态数组

时间:2019-02-25 14:34:26

标签: javascript reactjs api asynchronous

我正在尝试将状态变量设置为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的

无效。我想念什么?我已经尝试了无数在线修复程序,但似乎没有任何效果。

2 个答案:

答案 0 :(得分:1)

主要问题是forEach不会等待每个回调运行。在下面的示例中,done将被打印在数组元素(thing1thing2thing3)之前。

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)

setStateforEach完成之前被调用,这是一个简单的例子:

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