0

I have MyFunction() that populates a data source for my render's listView, and the process works on a local database and starts in the constructor of the screen.

Constructor:

constructor(props) {
    super(props);
    let MyDataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
    let MyData = MyFunction();
    let MyDataSource = MyDataSource.cloneWithRows(MyData);

    this.state = {
        Data: MyData,
        DataSource: MyDataSource,};
}

// ..

render() {  
    return (    
            <View>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow.bind(this)}
                    // .. 
                />
            </View>
     ); 
}  

Now, I want MyFunction() to retrieve data from a remote database, hence it is going to take sometime before data gets ready.

I want to display a "loading" message on the screen, then update the screen once data gets ready. And I modified my code as following:

 constructor(props) {
    super(props);
    let MyDataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
    let MyData = MyFunction(); // this is an async now, and will take sometime to finish
    let MyDataSource = MyDataSource.cloneWithRows(MyData);

    this.state = {
        Data: MyData,
        DataSource: MyDataSource,
        IsLoading: true, // so I added this
    };
}

// ..

async MyFunction() {

    // ..

    // this is what takes time now, and returns a promise, I use .then to set the final data
    // it is an async method that has a "await fetch()" inside it
    let dataFromServer = await getDataFromServer().then((response) => this.setState({isLoading: false, Data: response}));

    // ..
}    

render() {  
            if(this.state.isLoading)
            {
                return(
                <View style={styles.emptyListContainer}>
                    <Text style={styles.emptyListMessage}>
                        Loading Data ...
                    </Text>
                </View>
                )
            }
            return (    
                    <View>
                        <ListView
                            dataSource={this.state.dataSource}
                            renderRow={this.renderRow.bind(this)}
                            // .. 
                        />
                    </View>
            ); 
}

But this renders "Loading.." then empty. The reason is that the code after .then is being execute before .then is done (I guess?)

I am a little confused on how to achieve this since I am new to react native and js. Please and thanks

Khalil Khalaf
  • 9,259
  • 11
  • 62
  • 104

1 Answers1

1

At first, you don't need Data in state, as you don't use it at all.

To solve your problem you can use such constructor:

constructor(props) {
  super(props);
  
  getDataFromServer().then((response) => {
    let DataSource = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });
    
    this.setState({
      IsLoading: false,
      DataSource: DataSource.cloneWithRows(response)
    });
  });

  this.state = {
    IsLoading: true
  };
}
lunochkin
  • 684
  • 4
  • 17