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

Posted

技术标签:

【中文标题】如何在 React 中使用 fetch() API 来设置状态【英文标题】:How to use fetch() API in React to setState 【发布时间】:2018-09-15 23:25:15 【问题描述】:

我正在尝试在 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>
        );
    

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

【问题讨论】:

尝试将箭头函数传递给.then 你好!所以这行得通,但你能解释一下为什么箭头函数会产生如此大的不同吗?我以为箭头函数和函数的唯一区别是箭头函数没有被提升? 箭头函数将 this 绑定到声明上下文而不是执行上下文。 更多解释请看 mdn Arrow Function page in "No separate this" 部分 【参考方案1】:

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

例子:

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()

【讨论】:

【参考方案2】: this 指调用函数的对象。 每个普通函数都有自己的this,但箭头函数没有(这里的this 指的是外部上下文,即this 在函数之外。)。

所以可能的解决方案是

使用箭头功能
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);
            );

早先将this 保存在其他变量中并将其作为参数传递。 将this绑定到函数

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

【讨论】:

【参考方案3】:
 componentDidMount() 
    fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent')
      .then(response => response.json())
      .then(data => this.setState( apiInfo: data ));
  

在你的渲染函数中你不能只做this.state.apiInfo。该数据是一个对象数组,每个对象都有 username img 等键。如果您在render 函数内部和return 外部console.log(this.state.apiInfo),您可以看到。

要访问和显示数组值中的每个对象,您可以通过 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>
);

浏览器自带的原生 fetch API 使用 javascript Promise 来解析异步响应。

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

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

【讨论】:

这是一个我控制台记录的对象数组【参考方案4】:

您的错误消息准确地告诉您问题所在:

无法设置未定义的状态

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

this.setState(apiInfo: jsonStr);

是的,问题出在你的this。在您尝试调用它时 - 即在 .then()fetch 调用中 - this 实际上是未定义的。您可以在 Chrome Devtools 中看到这一点:

恐怕this 是 JavaScript 中的滑手;它的值可以(并且确实)根据您应用的当前上下文而改变。

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

以下是我如何将捕获 this 的 componentDidMount() 方法重新设计为 that,并在 .then() 中调用 that

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);
        );

如果您习惯使用箭头函数,那么另一种方法是将“正常”函数调用替换为一个,如下所示:

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

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

【讨论】:

哦好的,谢谢你的解释!我看到了关于使用箭头函数的解决方案,直到我看到这个并不太确定。如果我不使用箭头函数,您能否详细说明 fetch() API 中的“this”指的是什么?会不会是这里的全局对象?【参考方案5】:

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

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

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

或使用箭头函数

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

【讨论】:

以上是关于如何在 React 中使用 fetch() API 来设置状态的主要内容,如果未能解决你的问题,请参考以下文章

如何在带有 Jest 的 react-native 中使用模拟的 fetch() 对 API 调用进行单元测试

如何在 React 中处理 fetch API AJAX 响应

如何使用 React.js 中的 Fetch API 将数据发布到数据库

如何避免 React fetch API 替换 url

如何使用fetch(GET Call)设置超时react-native api调用?

如何在变量Fetch API中存储异步数据