react 在 componentWillMount() 中调用异步函数时,componentWillMount() finishes after render()

时间:2021-08-21 14:10:10

刚开始使用 react,很多属性、方法不是很熟。在此记录下我所遇到的问题及解决方法。

我在 componentWillMount() 中调用了一个异步函数,在返回结果中调用 this.setState() 来保存数据,在 render() 中使用 this.state.article 时,显示为 undefined。代码如下:

componentWillMount() {
  console.log('componentWillMount called')
  let _ = this
  // 获取当前文章 ID;
  let postID = utils.getID(ARTICLE)
  /**
   * @description 获取、渲染文章内容
   * @param {Number} postID - 当前文章 ID
   */
  postIO.getDetail(postID).then(res => {
    if (res.status === 200) {
      console.log('asynchronous called')
      let data = res.data
      _.setState({
        article: {...data},
              })
          }
  })
}
render() {
  console.log('render called')
  return (
    <div></div>
  )
}
可以看到控制台打印信息:
componentWillMount called
render called
asynchronous called
render called
这里可以得出:调用完 componentWillMount() 后,执行 render(),这时 componentWillMount 中的回调函数也执行完毕,更新数据后再次调用 render。
这个问题原因:首先,异步函数本身就是不会等前一个任务结束后再执行后一个函数,而是在执行其回调函数的同时就开始执行后一个函数了。因此,在调用完 componentWillMount 函数后,执行 postIO.getDetail(postID).then(res => {}),同时执行 render()。
可能导致的问题:在 componentWillMount 中的回调函数中调用 this.setState({article: {...data}}),第一次调用 render 时,是获取不到 this.state.article 的值的,这样就会引起报错。
解决方法:
增加一个加载状态,默认为 false,调用 componentWillMount() 时,设置为 true,当这个加载状态是 true 时,暂不渲染,当回调函数执行完毕后,设置为 false,此时再调用 render();
完整代码如下:
constructor(props) {
  super(props)
  this.state = {
    article: {},
    isLoading: false,
  }
}
componentWillMount() {
  let _ = this
  // 获取当前文章 ID;
  let postID = utils.getID(ARTICLE)
  _.setState({isLoading: true})
  /**
   * @description 获取、渲染文章内容
   * @param {Number} postID - 当前文章 ID
   */
  postIO.getDetail(postID).then(res => {
    if (res.status === 200) {
      console.log('asynchronous called')
      let data = res.data
      _.setState({
        article: {...data},
        isLoading: false
              })
          }
  })
}
render() {
  let {isLoading} = this.state
  if (isLoading) {
    return <p>isLoading...</p>
  }
  return (
    <div></div>
  )
}