react 在 componentWillMount() 中調用異步函數時,componentWillMount() finishes after render()

剛開始使用 react,不少屬性、方法不是很熟。在此記錄下我所遇到的問題及解決方法。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>
  )
}
相關文章
相關標籤/搜索