Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
   }
 }
like image 954
Matas Avatar asked Oct 19 '17 08:10

Matas


People also ask

How do I stop a component rendering?

It is done using stateVariable. The value of the stateVariable determines whether to render the component or not. Its value can be changed by the occurrence of any event like onClick.

How do you stop rendering when state changes?

To prevent the render method from being called, set the return to false, which cancels the render. This method gets called before the component gets rendered. Sometimes you may want to prevent re-render even if a component's state or prop has changed.

How do I stop render in useEffect?

You can add a condition in the call back function that checks if a certain condition is met, e.g. if data is empty. If it is empty, then fetch data, otherwise do nothing. This will prevent the infinite loop from happening.

How do I stop Rerendering the react?

Memoization enables our react code to re-render components only if there is an update in the props. With this approach, developers can avoid unnecessary re-renderings and reduce the computational load in applications. React provides two Hooks to create memoization: useMemo()


2 Answers

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})
 }
like image 101
Andrew Avatar answered Sep 18 '22 03:09

Andrew


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

like image 22
3Dos Avatar answered Sep 18 '22 03:09

3Dos