Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ListView append new data onLoadMore #100

Closed
vnshgrg opened this issue Dec 2, 2016 · 6 comments
Closed

ListView append new data onLoadMore #100

vnshgrg opened this issue Dec 2, 2016 · 6 comments

Comments

@vnshgrg
Copy link

vnshgrg commented Dec 2, 2016

I have a ListView which gets data from an array which is stored in state. when the user scrolls to the bottom of the list, onLoadMore fires up and it appends new data to the data array in state. This however does not renders appended array as Rows in my ListView. Am I missing something here?

@SoHotSoup
Copy link
Contributor

Hey @vnshgrg , could share your code with us? However, ListView renders its row depending on provided data prop.

@vnshgrg
Copy link
Author

vnshgrg commented Dec 2, 2016

@SoHotSoup Here's my code:

componentDidMount(){
  this._getFeed();
}

_getFeed = async function(){
  var id = this.props.user.data.id;
  var token = 'JWT '+ this.props.user.token;
  var limit = this.props.state.limit;
  var requestUrl = 'http://52.68.64.112:1337/feed/'+id+'/allFeed/'+limit;

  this.props.dispatch((dispatch) => {

    axios.get(requestUrl, {headers: {Authorization: token}})
      .then((response) =>{
        if(response.status === 200){
          if(limit === 1){
            this.props.dispatch(feedAction.getFeed(response.data.objects));
          }else{
            this.props.dispatch(feedAction.appendFeed(response.data.objects));
          }
        }else{
          // dispatch ERROR
          console.log(response);
        }

        this.props.dispatch(feedAction.incrementLimit(this.props.state.limit));
      }).catch((error) => {
        console.log(error);
      });
    });
}

_updateFeed(){
  this._getFeed();
}

_renderRow(feed){
  console.log(feed);
  return(
    <View styleName="stretch" style={{marginHorizontal: 5, marginTop: 10, borderRadius: 2}}>
        <Row>
          <Image
            styleName="respect-avatar"
            source={{ uri: feed.creatorId.profilePhoto}}
          />
          <View styleName="vertical stretch space-between">
            <Subtitle style={{fontSize: 18}}>{feed.creatorId.name}</Subtitle>
            <Caption>{Moment(feed.createdAt).fromNow()}</Caption>
          </View>
        </Row>
        <Row>
          <Text>{feed.message}</Text>
        </Row>
    </View>
  );
}

render() {
    return(

        <View styleName="flexible sm-gutter-horizontal" style={{marginTop: 64, marginBottom: 50, backgroundColor: '#f1f5f8'}}>
            <StatusBar
               barStyle="light-content"
             />
            
            <ListView 
              data={this.props.state.feeds}
              onLoadMore = {this._updateFeed.bind(this)}
              renderRow={this._renderRow.bind(this)}
            />
            
        </View>

    );
}

So, with this i am able to fetch array of data from the server using _getFeed method, populate my ListView with the data. i am also able to fetch for new data and append it to the state but the appended array of data is not rendered in the ListView. The shoutem/ui documentation have very less information so couldn't figure it out.

@SoHotSoup
Copy link
Contributor

It's hard to get it from this code snippet but seems to me that data isn't changed and always points to the same reference. Take a look at this line https://github.com/shoutem/ui/blob/develop/components/ListView.js#L116
ListView doesn't do deepEqual on data, but it expects a completely new array, so if reducer that handles appendFeed mutate state that wouldn't trigger new render on ListView.
I'm afraid that deep comparison on data object could have an impact on performance on larger sets of data.
So, I would advise you to try always create a new array in your reducers. If that is not an option, then you could just do this:

<ListView 
  data={[].concat(this.props.state.feeds)}
  onLoadMore = {this._updateFeed.bind(this)}
  renderRow={this._renderRow.bind(this)}
/>

@vnshgrg
Copy link
Author

vnshgrg commented Dec 2, 2016

Here's the reducer that handles data change. I am not sure if I am doing it correctly.

case "APPEND_FEEDS": {
	const prevState = state;
	action.payload.map((feed) => {
		prevState.feeds.push(feed);
	});

	const newFeeds = prevState.feeds;
	state = Object.assign({}, state, {feeds: newFeeds});
	break;
}

UPDATE: I used the data={[].concat(this.props.state.feeds)} method and it is working as per my expectation. Not sure if it will have performance issues. I am fairly new to React-native.

Thank you for helping me out @SoHotSoup, I am loving shoutem/ui and will be around.

@SoHotSoup
Copy link
Contributor

Ok, I was right about your reducer, you are mutating feeds.

Just change
const newFeeds = prevState.feeds to const newFeeds = [].concat(prevState.feeds)

After it, you can remove my previous suggestion and [].concat(data) will not be needed anymore.

Please close issue if you're satisfied with my answer.

@vnshgrg
Copy link
Author

vnshgrg commented Dec 2, 2016

Thank you very much. Works as expected.

@vnshgrg vnshgrg closed this as completed Dec 2, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants