如何从以前获取的数据更新React状态? [英] How do I update a React state from previously fetched data?

查看:148
本文介绍了如何从以前获取的数据更新React状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是React和JS的新手,并且仍然在学习,我试图创建一个网站来显示SWAPI API中的数据,尤其是People数据.如果我获取人员的第一页,则存在一个名为"next"的字段,该字段具有用于检索下一页的URL,依此类推.我希望能够在循环中使用此字段来获取所有数据页.这是第一页的示例:

I new to React and JS and still learning, I'm trying to create a website to show data from the SWAPI API, specifically the People data. If I fetch the the first page of people, there is a field called 'next' which has the url to retrieve the next page, as so on. I want to be able to use this field in a loop to fetch all the pages of data. Here's a sample of the first page:

{
    "count": 82,
    "next": "http://swapi.dev/api/people/?page=2",
    "previous": null,
    "results": [
        {
            "name": "Luke Skywalker",
            "height": "172",
            "mass": "77",
            "hair_color": "blond",
            "skin_color": "fair",
            "eye_color": "blue", ...

因此,一旦我获取了/people/,那么我就想获取/people/?page=2 这是我到目前为止的相关代码...

So once I have fetched /people/ then I would want to fetch /people/?page=2 Here's the relevant code I have so far...

class App extends Component {
    constructor() {
        super()
        this.state = {
            people: [],
            url: '',
            searchfield: ''
        }
    }
    // Find first page of 'people' then loop through each page adding 'data.results' to 'people' state array
    componentDidMount() {
        this.setState({ url: 'https://swapi.dev/api/people/' }, () => {
            console.log('initial url is', this.state.url)   
                for (var i = 0; i <= 3; i++) {
                    console.log('next url is', this.state.url)
                    fetch(this.state.url)
                    .then(response => response.json())
                    .then(data => this.setState((prevstate) => {
                        return {people: prevstate.people.concat(data.results), url: data.next}
                        }))
                    .catch(error => {
                        console.log(error)
                    });
                }
            });
        }

    componentDidUpdate(prevProps,prevState) {
        if(prevState.url !== this.state.url) {
            console.log('* new url is', this.state.url)
        }
    }

我现在有一个固定的循环i,直到我可以使其正常工作为止,否则它将无限循环. 我的问题是,当尝试使用下一页的地址更新url状态时,直到循环完成,它才发生,这是上面日志的输出.

I have a fixed loop i just now until I can get it working correctly otherwise it would loop indefinitely. My problem is that when trying to update the url state with the address of the next page it doesn't happen until the loop has finished, here's the output from the logs above.

* new url is https://swapi.dev/api/people/
initial url is https://swapi.dev/api/people/
4 next url is https://swapi.dev/api/people/  < this happens 4 times
* new url is http://swapi.dev/api/people/?page=2

我认为在return字段中添加状态更改就足够了,但是还不够,因此我尝试添加componentDidUpdate函数来尝试触发状态更改,但是我认为这没有帮助.我也很好奇,在什么都没有更新的情况下,如何首先显示来自componentDidUpdate的日志?

I thought adding the state change in the return field would be enough but is wasn't so I tried adding the componentDidUpdate function to try and trigger the state change, but I don't think it helped. I'm also curious how the log from componentDidUpdate appears first when nothing has been updated yet?

目前,所有这些操作都是将相同的4个页面连接到people数组中(控制台对此有所抱怨).

At the moment all this does is concatenate the same 4 pages into the people array (and the console complains about it).

所以我的问题是,如何使用上一次提取的数据正确设置url状态?

So my question is, how can I set the url state correctly using data from a previous fetch?

好的,我忘记添加到我的问题中的一件事是,我正计划使此访存泛型化,以便它可以接受SWAPI上的任何类别,并使用下一个"字段来确定何时停止访存数据.我确实有一段类似于Yousafs答案的代码,我获取了第一页,然后使用count遍历了所有单独的页面,但这意味着要进行72次获取!那是浏览页面似乎更好的选择.我现在有个更好的主意.

Ok, one thing I forgot to add to my question is that I was planning on making this fetch generic so that it could accept any of the categories on SWAPI and use the 'next' field to determine when to stop fetching data. I did have a previous piece of code which was similar to Yousafs answer, I fetched the first page then used the count to loop through all the individual pages, but that meant 72 fetches! that's when looping through the pages seemed a better bet. I have a better idea how to do that now.

推荐答案

您在循环中获取数据的方法是完全错误的. fetch函数返回一个Promise,并且实际请求是异步进行的.您应该做的是将fetch函数返回的所有promise保存在一个数组中,然后使用 Promise.all()函数.

Your approach to fetch data in a loop is all wrong. fetch function returns a promise and the actual request is made asynchronously. What you should do is save all the promises returned by fetch function in an array and then resolve all those promises using Promise.all() function.

要获取所需的数据,请按照以下步骤操作:

To fetch the data you want, follow these steps:

    componentDidMount函数中的
  1. 中,创建一个数组,该数组将保存fetch函数返回的所有promise.创建一个循环,并将fetch函数返回的所有promise添加到您先前创建的中.

  1. in componentDidMount function, create an array that will hold all the promises returned by fetch function. The create a loop and add all the promises returned by fetch function in the you created previously.

之后,调用Promise.all函数并传递包含所有promise的数组. Promise.all将返回响应对象的数组.然后,您需要调用 .json()函数在所有这些Response对象上获取API返回的实际数据.

After that, call Promise.all function and pass the array that contains all the promises. Promise.all will return an array of Response objects. Then you need to call .json() function on all those Response objects to get the actual data returned by the API.

这是您的componentDidMount函数的外观.

here's how your componentDidMount function should look like.

componentDidMount() {
    const requests = [];

    for (let i = 1; i <= 3; i++) {
      requests.push(fetch('https://swapi.dev/api/people/?page=' + i));
    }

    Promise.all(requests)
      .then(res => Promise.all(res.map(r => r.json())))
      .then(data => {
        const people = [];

        data.forEach(d => people.push(...d.results));

        this.setState({ people });
      })
      .catch(err => console.log(err.message));
}

上述componentDidMount函数也可以使用编写async-await 语法.

above written componentDidMount function can also be written using async-await syntax.

async componentDidMount() {
    const requests = [];

    for (let i = 1; i <= 3; i++) {
      requests.push(fetch('https://swapi.dev/api/people/?page=' + i));
    }

    try {
      const responseArr = await Promise.all(requests);
      const data = await Promise.all(responseArr.map(r => r.json()));

      const people = [];
      data.forEach(d => people.push(...d.results));

      this.setState({ people });

    } catch(error) {
      console.log(error.message);
    }
}

演示

这是一个演示,可从中获取前3页的数据Swapi API并显示所有人的姓名.

Demo

Here's a demo that fetches data of first 3 pages from the Swapi API and displays the names of all the people.

这篇关于如何从以前获取的数据更新React状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆