How do I stop a component rendering before data is fetched?

蓝咒 提交于 2020-07-17 05:54:32

问题


Currently in react I have to functions in the componentDidMount lifecycle method in which call action creators to which fetch data. The component uses the data however, depending on how quick the response is determines if the data is there or not. How can i make it so the component doesn't render before data is inside it?

componentDidMount() {
    this.props.getTotalHours()
    this.props.getTrained()
  }

Render Function:

render() {
    let hours = parseInt(_.map(this.props.hours, 'hours'));
    let trained = _.map(this.props.trained, 'trained');
    return (
      <div className="o-layout--center u-margin-top-large">
          <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
            <div style={{width: '80%', margin: '0 auto'}}>
              <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
            </div>
          </div>

Action Creator stores returned values from request in the application state:

 export function getTotalHours() {
   const url = `${ROOT_URL}dashboard/hours`
   const request = axios.get(url)
   return {
     type: FETCH_HOURS,
     payload: request
   }
 }

回答1:


Control your async actions using then or await and use this.state to control whether or not your content gets loaded. Only render your content after this.state.loaded === true

constructor(props) {
  super(props)
  this.state = {
    loaded: false
  }
}

async componentDidMount() {
    await this.props.getTotalHours()
    await this.props.getTrained()
    this.setState({loaded: true})
  }

content() {
  let hours = parseInt(_.map(this.props.hours, 'hours'));
  let trained = _.map(this.props.trained, 'trained');
  return (
    <div className="o-layout--center u-margin-top-large">
    <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
      <div style={{width: '80%', margin: '0 auto'}}>
        <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
      </div>
    </div>
  )
}

render() {
  return (
  <div>
    {this.state.loaded ? this.content() : null}
  </div>
  )
}

edit: If you care about performance in your API calls, you can run them in parallel with Promise.all.

async componentDidMount() {
   const hours = this.props.getTotalHours()
   const trained = this.props.getTrained()
   await Promise.all([hours, trained])
   this.setState({loaded: true})
 }



回答2:


In your constructor, declare a state variable to track if data is loaded. For example:

constructor (props) {
  super(props)
  this.state = {
    dataLoaded: false
  }
}

Then in your render method, return null if this.state.dataLoaded is false:

render () {
  const { dataLoaded } = this.state
  return (
    <div>
      {
        dataLoaded &&
        <YourComponent />
      }
    </div>
  )
}

And in the methods you use to fetch data, make sure you call this.setState({ dataLoaded: true }) when data has been fetched




回答3:


You can't stop the render but you can give conditions to what to render.

Example

render() {
    if(this.props.hours. length <= 0 || this.props.trained.length <= 0 ) {
      return (<div><span>Loading...</span></div>);
    } else {
      let hours = parseInt(_.map(this.props.hours, 'hours'));
      let trained = _.map(this.props.trained, 'trained');
      return (
        <div className="o-layout--center u-margin-top-large">
            <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
              <div style={{width: '80%', margin: '0 auto'}}>
                <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
              </div>
            </div>
      )
    }


来源:https://stackoverflow.com/questions/46825735/how-do-i-stop-a-component-rendering-before-data-is-fetched

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!