杭州电子商务研究院

在 Promise 的 Catch 块中访问“this”

2020-10-30 08:00飞浪

介绍

Promises 是 JavaScript 编程语言的革命性补充。在 Promises 出现之前,需要将回调传递给函数调用才能对异步控制流进行建模。Promises 为您提供了一种更易读、更易于维护的方式来管理 React 应用中的异步操作。Promise提供的then和catch函数使您能够异步链接函数并处理错误。但是,在范围和this关键字方面,在 React 组件中使用 Promise 可能会造成混淆。在 JavaScript 中,this关键字允许您访问周围词法范围的上下文对象。在本指南中,您将学习如何确保您的 promise catch块在 React 组件中使用正确的上下文,以便您可以通过this轻松访问组件属性。

让我们开始吧!

绑定组件范围

首先,问题来了。在 React 组件中使用 Promise 时,你的第一反应可能是这样处理 Promise:

      // ... MammalComponent.jsx

fetchMammals() {
    return fetch(this.mammalsUrl)
             .then(function(response) {
                return response.json();
             });
}

initMammalsState() {
    const mammalJsonPromise = this.fetchMammals();
    mammalJsonPromise
        .then(function(mammals) {
            this.setState({ mammals });
        })
        .catch(function(error) {
            this.error = error;
        });
}


// ...
    

乍一看,这段代码似乎可以工作。它只是使用Fetch API 来获取一些 JSON,然后处理返回的 Promise。如果在catch块中发生错误,它还会在组件本身上设置error属性。但不幸的是,这段代码失败了!如果你使用上面的代码创建一个组件,你可能会看到一个类似于Can't find property <prop-name> of undefined 的错误。这是因为你的 Promise 无法访问正确的this上下文!

解决此问题的第一个方法是使用JavaScript函数原型上提供的bind函数。bind函数允许您将this上下文注入您正在使用的函数的范围。下面,您将看到上面的函数经过重构以利用此功能。请注意,甚至组件函数本身也绑定到构造函数中的React 组件的this上下文。

      // ... MammalComponent.jsx

constructor(props) {
    super(props);

    // Bind the 'this' context of the component to our class functions
    this.fetchMammals = this.fetchMammals.bind(this);
    this.initMammalsState = this.initMammalsState.bind(this);
}

fetchMammals() {
    return fetch(this.mammalsUrl)
             .then(function(response) {
                return response.json();
             });
}

initMammalsState() {
    const mammalJsonPromise = this.fetchMammals();
    mammalJsonPromise
        .then(function(mammals) {
            this.setState({ mammals });
        }.bind(this))
        .catch(function(error) {
            this.error = error;
        }.bind(this));
}


// ...
    

在上面这个简单的解决方案中,您可以看到如何使用bind函数将 this 的上下文绑定到catch块中,以便组件可以显示错误。这有效……但还有更好的方法!在下一节中,您将看到如何使用箭头函数来大大简化这一过程。

使用箭头函数绑定组件范围

箭头函数不仅仅是一种简洁的函数声明方式。箭头函数还为您隐式绑定了this关键字!在下面的代码中,您将看到我们如何通过箭头函数访问MammalsComponent的error属性。

      // ... MammalComponent.jsx

// We don't have to bind these functions anymore!
fetchMammals = () => fetch(this.mammalsUrl).then(response => response.json())

initMammalsState = () => {
    const mammalJsonPromise = this.fetchMammals();

    mammalJsonPromise
        .then(mammals => this.setState({ mammals }))
        .catch(error => this.error = error);
}

// ...
    

哇!看看代码有多简单!此代码不仅有效,而且更简洁、更易于维护。catch块现在可以访问MammalComponent的范围,因此它现在可以设置错误属性。

结论

箭头函数是将 React 组件范围的上下文绑定到组件内的内部函数的最佳方式。以这种方式使用箭头函数可让您有效地访问Promise catch块内的this属性。

上述代码还可以进行一些额外的改进,即使用 async/await 语法。JavaScript 关键字 async 和 await 可以简化承诺的使用,并减少代码库中的嵌套代码量。它还允许您以同步方式对异步代码进行建模。有关更多信息,请查看async/await 语法的文档。

曝光28625浏览1563