Phil
Phil

Reputation: 3994

React-native ListView DataSource not updating

Been pulling my hair for a while now and can't get the dataSource to be updated. I've looked at other posts but can't see why this doesn't work. I've debugged and can see the proper json being returned, so the data is there.

var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

var ReviewList = React.createClass({
  _getMovieReviews: function() {
    var _urlForReview = this.props.config.api_url + 'movies/' + 
    this.props.movie.id + '/reviews.json?apikey=' + this.props.config.api_key;
            this.setState(function(){
          dataSource: ds.cloneWithRows(['before fetch']);  
        });
    fetch(_urlForReview)
      .then(function(res) {
        return res.json();
      }).then(function (json){
        console.log(json);
        this.setState(function(){
          dataSource: ds.cloneWithRows(['fetch done']);  
        });
    });
  }, 
  getInitialState: function() {
    return {
      dataSource: ds.cloneWithRows(['initial'])
    };
  },
  componentDidMount: function() {
      this._getMovieReviews();
  },

render: function() {
  return (
     {rowData}}
    />
  );
}
});

For now I'm even just trying to update the datasource to anything else than the original value. What am I missing here?

update

Neither "before fetch" or "fetch done" are shown. Only "initial". I'm suspecting that it has to do with that there are other components in the class. Not sure if that could be the case.

update I inserted the sample code one of the answers provided and the sample works in the same view. Super weird. Probably something very stupid I'm missing here...

update It seems the problem lies with updating the datasource from within the fetch statement.

Upvotes: 1

Views: 1366

Answers (1)

Nader Dabit
Nader Dabit

Reputation: 53711

You need to set it up so that the datasource gets reset on componentDidMount:

  getInitialState: function() {
    return {
      dataSource: ds.cloneWithRows([])
    };
  },

  componentDidMount: function() {
        this._getMovieReviews()  
  },

  _getMovieReviews: function() {
    // Go to api and get movies, then...
    this.setState({
        dataSource: ds.cloneWithRows(movieReviewsFromApi)
    })
  },

Let me know if this answers your question. I've set up a full working project here. The code is also below.

https://rnplay.org/apps/P-em5Q

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ListView,
} = React;

var movieReviewsFromApi = [
  {name: 'Die Hard', review: 'Best movie ever'}, {name: 'Home Alone 2', review: 'Great movie'}, {name: 'Bourne Identity', review: 'Awesome Movie'}
  ]

var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

var SampleApp = React.createClass({

  getInitialState: function() {
    return {
      dataSource: ds.cloneWithRows([])
    };
  },

  componentDidMount: function() {
        this._getMovieReviews()  
  },

  _getMovieReviews: function() {
    this.setState({
        dataSource: ds.cloneWithRows(movieReviewsFromApi)
    })
  },

  _renderRow: function(rowData) {
    return (<View style={{height:70,borderBottomColor: '#ededed', borderBottomWidth:1, paddingLeft:10, paddingTop:10}}>
                <Text style={{fontSize:22}}>{rowData.name}</Text>
              <Text style={{color: '#666'}}>{rowData.review}</Text>
            </View> )
  },

  render: function() {
    return (
    <View style={{ marginTop:60 }}>
        <ListView
      dataSource={this.state.dataSource}
      renderRow={this._renderRow}
    />
    </View>
  );
  }
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);

Upvotes: 2

Related Questions