componentDidMount 回调处理规范问题

如下组件:

class Demo extends React.Component {
  constructor(props) {
    ...
  }
  async componentDidMount(){
    await actions.doingSomething(query);
    doingOthers();
    ....
  }
}

换句话说:

async await 用在componentDidMount生命周期是否符合react规范

阅读 6.7k
4 个回答

可以这样

...
componentDidMount(){
    this.getData()
}
...
async getData() {
    await actions.doSomething()
}

你用的是哪个版本的ReactJs? 我记得ReactJs似乎是不会使用await来等待componentDidMount完成的。一般来说componentDidMount里面的操作应该尽量简单才对。

没见过这种用法哎

首先明确一点,componentDidMount() 在组件的整个生命周期函数内只会执行一次,即组件初次加载完成之后被触发。因此适合在此生命周期方法内执行异步操作。

先多说几句,跑跑题:async/await 是 ES7 新增的语法,算是 Generator 语法糖。注意 Generator 函数虽然是异步编程的一种解决方案,但其本身是同步的,适合异步编程的原因是其独特的执行方法,有很强的可控性(其实就是迭代器的执行),其实理解这个很重要。我认为要真正学会 Async/Await,必须弄懂 Iterator 和 Generator

回来。当我们给一个函数添加上 async 关键字变成 Async 函数,它只做了一件事情:让该函数返回一个 Promise 对象仅此而已。当它发挥真正实力的时候,是结合 await 关键字使用(注意,Async 函数内的 await 是可选的,但函数内部不使用 await 将失去它的意义)。

当一个 Async 函数内不使用任何 await 关键字,它只会变成一个返回 Promise 对象的普通的、“同步”的函数。

当我们要写一个 Async 函数时,通常表示其内部应该有一个或多个异步操作(一个的话,我认为直接用 Promise 即可)。结合 await 可以用同步的写法去处理异步操作,使其按“顺序”执行,这也是它备受欢迎的原因。它的用法很简单,就不说了。

但还是那句话,要真正了解 Async/Await 应要弄懂 Generator 函数。大家项目中很少写 Generator 函数的原因是,要自实现一个执行器去执行 Generator 函数,而前面说到 Async 函数是 Generator 的语法糖,原因是内部自带了一个执行器而已,极大地方便了使用者。在此之前,应该是 co + Generator 结合居多吧,因为 co 库实现了一个 Generator 函数的执行器。

至于你在 componentDidMount() 加上 async 使其变成 Async 函数,请不必有任何负担。因为 React 内部不会读取 componentDidMount() 方法的返回值,因此你可以返回任何的值,也包括返回一个 Promise 对象,但是没有意义的。我们把 componentDidMount() 就当成一个普通函数去看,举个例子:

function foo() {
    // do something...
    // 如果你要写异步操作,可能就要借助回调函数、Promise 等去控制了
}

async function bar() {
    // do something...
    // 不管你这里面有没有 await 或其他异步操作
}

// 下面我们只是调用了,但没有取其返回值,
// 因此,无论是不是 Async 函数,其实没关系,就这里而已,其返回值是没有意义的。
// componentDidMount 同理。
foo()
bar()

因此,在 componentDidMount() 使用 async 关键字,并不会说不符合 React 使用哲学。

就比如:

import React, { useState } from 'react'

function Foo(props) {
    // 我相信写 State Hook 看到的写法 99% 肯定是以下这样的(只是一个数组解构而已)。
    const [count, setCount] = useState(0)

    // 而不会这样去写(当然这样写是完全没问题的哈)
    // const state = useState(0)
    // const count = state[0]
    // const setCount = state[1]

    return <div>{ count }</div>
}

不用下面的写法,有两个好处:一是语法简洁,省了很多行代码,尤其在 state 众多的时候,尤为明显;二是语义更清晰。

说了那么多,就你的疑问,说一句:它不会破坏 React 哲学,请放心使用。

但是,请合理使用 Async/Await,正是由于它语法太简单了,很容易“误用”。例如有两个网络请求,且它们是没有关联的。因此是可以并发发起的,但有些人一不留神可能就直接写成继发了,程序执行时间瞬间变成了两倍。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题