Javascript 如何在 React 中使用 fetch() API 来设置状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49684217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:26:45  来源:igfitidea点击:

How to use fetch() API in React to setState

javascriptreactjspromisefetch

提问by albert

I'm trying to write a component in React that will use the fetch() API to get data from a website, then use setState to set a state equal to the data, and then finally render the data. My code looks like this:

我正在尝试在 React 中编写一个组件,该组件将使用 fetch() API 从网站获取数据,然后使用 setState 设置与数据相等的状态,最后呈现数据。我的代码如下所示:

import React from 'react';

export default class Test extends React.Component {
    constructor(props){
        super(props);
        this.state = {apiInfo: 'default'};
    }

    componentDidMount(){
        fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(
            function(response){
                return response.json();
            }
            ).then(function(jsonData){
                return JSON.stringify(jsonData);
            }
            ).then(function(jsonStr){
                this.setState({apiInfo: jsonStr});
                console.log(jsonStr);
            });
    }

    render(){
        return(
                <tr>
                    <td>{this.state.apiInfo}</td>
                </tr>
        );
    }
}

However, this results with an error saying I'm unable to setState of undefined. I end up rendering 'default' on my HTML. What exactly am I doing wrong here?

但是,这会导致错误提示我无法设置未定义的状态。我最终在我的 HTML 上呈现“默认”。我到底做错了什么?

回答by ChillyPenguin

Your error message is telling you exactly what the problem is:

您的错误消息准确地告诉您问题是什么:

unable to setState of undefined

无法设置未定义的状态

So you're trying call setStateas a method of an object that doesn't exist at that point. As a property of what object are you trying to call setStateas a method?

因此,您正在尝试将 callsetState作为当时不存在的对象的方法。作为什么对象的属性,您试图将其setState作为方法调用?

this.setState({apiInfo: jsonStr});

this.setState({apiInfo: jsonStr});

Yes, it's your thisthat's the problem. At the point that you're trying to call it - i.e. inside a .then()of a fetchcall - thisis actually undefined. You can see this in the Chrome Devtools:

是的,那是你this的问题。在点你想叫它-即内.then()一的fetch电话-this实际上是不明确的。您可以在 Chrome Devtools 中看到这一点:

Chrome Devtools shows this=undefinedI'm afraid that thisis a slippery customer in JavaScript; its value can (and does) change depending upon the current context of your app.

Chrome Devtools 显示 this=undefined恐怕这this是 JavaScript 中的一个狡猾的客户;它的值可以(并且确实)根据您的应用程序的当前上下文而变化。

There's several ways you can workaround this. One slightly clunky (but it works!) way is to capture your thisvalue before you enter your .fetch() call, and assign it to another variable. You'll often see thator selfvariables used for this purpose, but they're just conventions. You can call the variable what you like.

有几种方法可以解决此问题。一种稍微笨拙(但它有效!)的方法是this在您输入 .fetch() 调用之前捕获您的值,并将其分配给另一个变量。您会经常看到用于此目的的thatself变量,但它们只是约定。您可以随意调用变量。

Here's how I've reworked your componentDidMount() method capturing thisto that, and calling thatinside the .then():

这是我如何重新设计您的 componentDidMount() 方法捕获thisthat,并that在 内部调用.then()

componentDidMount() {
    const that = this;
    fetch("https://fcctop100.herokuapp.com/api/fccusers/top/recent")
        .then(function(response) {
            return response.json();
        })
        .then(function(jsonData) {
            return JSON.stringify(jsonData);
        })
        .then(function(jsonStr) {
            that.setState({ apiInfo: jsonStr });
            console.log(jsonStr);
        });
}

If you're comfortable using arrow functions, then another way is to replace your "normal" function call with one, like so:

如果你习惯使用箭头函数,那么另一种方法是用一个替换你的“普通”函数调用,如下所示:

.then(jsonStr => {
    this.setState({ apiInfo: jsonStr });
    console.log(jsonStr);
});

An arrow function's thisis always the thisthat its parent defined.

箭头函数this始终是this其父定义的。

回答by illiteratewriter

It is saying setStateis undefined because you're accessing it in the wrong context. You can either, convert the function into an arrow function or bind it to the right context. Hereis an article as to When and why do we bind this to the React component method.

它说setState是未定义的,因为您在错误的上下文中访问它。您可以将函数转换为箭头函数或将其绑定到正确的上下文。是一篇关于何时以及为什么将其绑定到 React 组件方法的文章。

In your code, the change that can be made is either binding it

在您的代码中,可以进行的更改是绑定它

.then(function(jsonStr){
          this.setState({apiInfo: jsonStr});
          console.log(jsonStr);
      }.bind(this));

or using arrow function

或使用箭头功能

.then((jsonStr)=>{
          this.setState({apiInfo: jsonStr});
          console.log(jsonStr);
      });

回答by Rohit Kaushal

  • thisrefers to the object which calls the function.
  • every normal function has its own thishowever arrow functions does not (thishere refers to the outside context i.e., what thisis outside the function.).
  • this指调用函数的对象。
  • 每个普通函数都有自己的this但箭头函数没有(this这里指的是外部上下文,即this函数之外的内容。)。

So the possible solutions are

所以可能的解决方案是

  • Use Arrow function
  • 使用箭头功能
componentDidMount = () => {
    fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(
            function(response){
                return response.json();
            }
            ).then(function(jsonData){
                return JSON.stringify(jsonData);
            }
            ).then(function(jsonStr){
                this.setState({apiInfo: jsonStr});
                console.log(jsonStr);
            });
}
  • save thisin some other variable earlier and pass it as argument.
  • Bind thisto the function
  • 之前保存this在其他一些变量中并将其作为参数传递。
  • 绑定this到函数

https://reactjs.org/docs/handling-events.html

https://reactjs.org/docs/handling-events.html

回答by MLH

Write the fetch code into separate method, then you will be able to call this.setState({}) inside the ".then(..)" statement after adding a bind to the new function inside the constructor.

将fetch代码写入单独的方法中,然后在构造函数内部添加绑定到新函数后,您将能够在“.then(..)”语句中调用this.setState({})。

Example:

例子:

constructor(props){
     super(props)
     ...
     this.myFunc = this.myFunc.bind(this)
}

myFunc = () => {
    fetch('...')
       .then(response => response.json())
       .then(data => this.setState({ apiInfo: data }));
}

componentDidMount() {
    this.myFunc()
}

回答by Omar

 componentDidMount() {
    fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent')
      .then(response => response.json())
      .then(data => this.setState({ apiInfo: data }));
  }

In your render function you cannot just do this.state.apiInfo. This data is an array of objects, each object has keys like usernameimgand more. You can see that if you console.log(this.state.apiInfo)inside the renderfunction and outside the return.

在您的渲染功能中,您不能只执行this.state.apiInfo. 这个数据是一个对象数组,每个对象都有像这样的键usernameimg。您可以看到,如果您console.log(this.state.apiInfo)render函数内部和return.

To access and display the each object inside of the arrays values you can mapthrough your apiInfoarray.

要访问和显示数组值中的每个对象,您可以map通过 apiInfo数组。

render() {
const { apiInfo } = this.state;
apiInfo && console.log(apiInfo.map(item => item.img));
return (
  <div>
    {apiInfo &&
      apiInfo.map(item =>  <div> {item.img} </div> )}
  </div>
);
}

The native fetch API that comes with the browser uses JavaScript promises to resolve the asynchronous response.

浏览器附带的原生 fetch API 使用 JavaScript 承诺来解决异步响应。

When the data is fetched successfully, it will be stored in the local state with React's this.setState() method. Then the render() method will trigger again and you can display the fetched data.

当数据获取成功时,它会通过 React 的 this.setState() 方法存储在本地状态中。然后 render() 方法将再次触发,您可以显示获取的数据。

Arrow functions were introduced in ES6, and an arrow function does not have its own context and will instead use the same thisas the context in which it was defined. We can use this fact and pass in an arrow function to the callback.

ES6 中引入了箭头函数,箭头函数没有自己的上下文,而是使用与this定义它的上下文相同的上下文。我们可以使用这个事实并将箭头函数传递给回调。