Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: How to wait data before using "this.state.x" into a function?

I'm currently learning React, and some stuff are not so easy for a newbie...

I have a simple component which renders this (note that it renders a li array thanks to function getSlots):

render () {
    return (
        <ul>
          {this.getSlots(this.state.viewing).map(item => <li key={item}>{item}</li>)}
        </ul>
    )
  }

Function getSlots is:

constructor (props) {...}

getSlots (viewing) {

    SOME STUFF...

    const monday = this.state.house.monday

    return SOME STUFF...
  }

componentDidMount () {...}

render () {...}

The point is that getSlots needs data to be fetched in componendDidMount to work. Indeed, at this time, getSlots doesn't work (it crashes) because it runs before data are fetched (this.state.house.monday is "empty" when it runs).

How do I wait for data to be fetched before running getSlots? Thanks for your clue.

like image 454
charnould Avatar asked Dec 13 '22 19:12

charnould


2 Answers

You're going to need to conditionally render. Provide a loading state to be loaded prior to asynchronously required data. You'll want something like the following:

class WrapperComponent extends PureComponent {
    constructor(props) {
        super(props);

        this.state = {
            isLoaded: false,
            data: null
        };
    }

    componentDidMount() {
        MyApiCall.then(
            res => this.setState({
                // using spread operator, you will need transform-object-rest-spread from babel or
                // another transpiler to use this
                ...this.state, // spreading in state for future proofing
                isLoaded: true,
                data: res.data
            })
        );
    }

    render() {
        const { isLoaded, data } = this.state;
        return (
            {
                isLoaded ?
                    <PresentaionComponentThatRequiresAsyncData data={ data } /> :
                    <LoadingSpinner /> // or whatever loading state you want, could be null
            }
        );
    }
}
like image 82
Kyle Richardson Avatar answered Dec 16 '22 08:12

Kyle Richardson


constructor() {
  super()
  this.state = { isLoading: true }
}

componentDidMount() {
  ('fetch data').then(() => { this.setState({ isLoading: false }); })
}

render() {
  return (
    <div>
      {!this.state.isLoading && ('your code')}
    </div>
  );
}

Something like that.

like image 38
Maxim Saenko Avatar answered Dec 16 '22 08:12

Maxim Saenko