【问题标题】:How to use fetch() API in React to setState如何在 React 中使用 fetch() API 来设置状态
【发布时间】: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" 部分

标签: javascript reactjs promise fetch


【解决方案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);
            });
      

      【讨论】:

        猜你喜欢
        • 2019-07-31
        • 2019-07-31
        • 1970-01-01
        • 1970-01-01
        • 2019-09-07
        • 1970-01-01
        • 2021-06-06
        • 1970-01-01
        • 2021-02-02
        相关资源
        最近更新 更多