React-native: ViewPagerAndroid returns empty view when new source data added

Created on 15 Dec 2015  路  20Comments  路  Source: facebook/react-native

I am currently using the ViewPagerAndroid component to do a matching/unmatching function which requires dynamic data updating in the source data of the component. The children of of the view pager is generated by a function makeItems(this.state.data) and it returns an array of keyed views. i.e. [< View key={1}/>, < View key={2}/>....] with the index being the index of the for loop that generates the array from the source data. The views contain composite views of touchable highlight but all are wrapped by a view container. I kept the data in the state of the component and whenever data updates I call setState and ViewPagerAndroid.setPage(0). The data update works fine when I reduce the data (splice) but returns an empty view for the new data when I add new data to the array. The data before the update was displayed properly.I have checked my makeItems() function that the updated data has been passed in proper.

< ViewPagerAndroid
          name = 'Page Viewer 1'
          style = {styles.matchingPanelViewPager}
          initialPage={this.state.currentPage}
          onPageSelected = {(e)=>{
            console.log(e.nativeEvent.position);
          }}
          ref = {viewPager =>{this.viewPager = viewPager;}}>

          { this.makeItems(this.state.data) }

        </ ViewPagerAndroid>

I am using RN0.16.0 on Mac OS X, Genymotion, Android 4.2.2.

Same issue raised in StackOverflow: http://stackoverflow.com/questions/34279503/viewpagerandroid-returns-empty-view-when-new-source-data-added
Thanks a lot for your help!

Locked

Most helpful comment

@Richard-Cao, this works for me <ViewPagerAndroid key={pageCount}....

Thanks a lot @yonatanmn

All 20 comments

Hey ACCTFORGH, thanks for reporting this issue!

React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.

  • If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on StackOverflow with the tag react-native or for more real time interactions, ask on Discord in the #react-native channel.
  • If this is a feature request or a bug that you would like to be fixed, please report it on Product Pains. It has a ranking feature that lets us focus on the most important issues the community is experiencing.
  • We welcome clear issues and PRs that are ready for in-depth discussion. Please provide screenshots where appropriate and always mention the version of React Native you're using. Thank you for your contributions!

Hi.
I'm facing the same issue.
I have a pager that renders an array of views.
When I deleted an entry of the array, the next render of the pager is drawing an empty view.
Also, the last view of the array goes out of screen bounds and cant be reached.

I dont really know where I have to start looking to fully realize whats really happen

Regards

I ran into this too and my temporary solution was to give it a key, then change that key every time you update the data source. A PR is welcome to fix this!

I used this third party component and it works well with data updates. The syntax is more elegant too.

https://github.com/race604/react-native-viewpager

Having the same issue (actually adding is ok, but slicing array of pages, and pushing causes this).
I've tried changing key (to AndroidViewPager) according to @brentvatne proposal, but then other problems occurred - no animation sometimes, and after some fast changes errors spawned.

I know there are problems with the native android component (look here), so maybe the solution should start there.
But actually the best solution (for my desires) will be to add pagingEnabled to ScrollView in android, and than even deprecate AndroidViewPager.

BTW, Iv'e tried the third party solution @ACCTFORGH suggested, but it's really low performant.

PLEASE VOTE FOR THIS BUG

any solution? same here. update data but return a empty view

In my scenario I'm either appending a page or slicing and then appending to the sliced pages array,

What currently works for me is adding key based on time on this condition:
androidViewPagerKey = newPages.length < pages.length ? Date.now() : androidViewPagerKey return <ViewPagerAndroid key={androidViewPagerKey}...

any solution?

@Richard-Cao, this works for me <ViewPagerAndroid key={pageCount}....

Thanks a lot @yonatanmn

Thx, I wil try. @thrap

Having the same issue. Using a new key for the ViewPagerAndroid Component solves this for now, but it is not an efficient solution, when only certain pages of the ViewPager should be replaced.

Faced the same issue, and there is a fix for this.

Actually the implementation of ReactViewPager.java is incomplete.

Following method should be implemented also:

    @Override
    public int getItemPosition(Object object) {
      int index = mViews.indexOf(object);
      if (index >= 0) return index;
      return PagerAdapter.POSITION_NONE;
    }

Next, following method also should be fixed:

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
      View view = (View) object;
      container.removeView(view);
    }

In my case, I copied com.facebook.react.views.viewpager classes to my project, fixed it and exported it as my own native view using same name. Now ViewPagerAndroid pages are properly created and destroyed reflecting changes of children array

Hi there! This issue is being closed because it has been inactive for a while.

But don't worry, it will live on with ProductPains! Check out its new home: https://productpains.com/post/react-native/viewpagerandroid-returns-empty-view-when-new-source-data-added

Product Pains has been very useful in highlighting the top bugs and feature requests:
https://productpains.com/product/react-native?tab=top

Also, if this issue is a bug, please consider sending a pull request with a fix.

@kvj Do you want to send a PR adding those methods?

+1 for a fix. I think it's important because we can't have infinite viewpagers otherwise in Android.

its def. still a problem version: 0.44.3 yonatanmn's solution with setting a key = current timestamp on the viewPager itself fixes. its fine for now. or till 2038 :)

Adding a dynamic key fixes the problem. But if I do i.e. key={pages.length} (so the key changes whenever the number of children changes) I experience a flickering behaviour if the key changes.

Have you tried the virtualizedList with pagingenabled?
On iOS that works perfect for an infinite viewpager.

The problem is specifically related to android.

I know but maybe is ViewPagerAndroid not the way to go. I have an infinite viewpager made with VirtualizedList. I'm sure you'll need some customizing

import React, { Component } from 'react'
import { View, Text, Dimensions, VirtualizedList } from 'react-native'

const { width, height } = Dimensions.get('window')
const startAtIndex = 5000
const stupidList = new Array(startAtIndex * 2)

class InfiniteViewPager extends Component {
  //only use if you want current page
  _onScrollEnd(e) {
    // const contentOffset = e.nativeEvent.contentOffset
    // const viewSize = e.nativeEvent.layoutMeasurement
    // // Divide the horizontal offset by the width of the view to see which page is visible
    // const pageNum = Math.floor(contentOffset.x / viewSize.width)
  }
  _renderPage(info) {
    const { index } = info

    return (
      <View style={{ width, height }}>
        <Text>
          {' '}{`index:${index}`}{' '}
        </Text>
      </View>
    )
  }
  render() {
    return (
      <VirtualizedList
        horizontal
        pagingEnabled
        initialNumToRender={3}
        getItemCount={data => data.length}
        data={stupidList}
        initialScrollIndex={startAtIndex}
        keyExtractor={(item, index) => index}
        getItemLayout={(data, index) => ({
          length: width,
          offset: width * index,
          index,
        })}
        maxToRenderPerBatch={1}
        windowSize={1}
        getItem={(data, index) => ({ index })}
        renderItem={this._renderPage}
        onMomentumScrollEnd={this._onScrollEnd}
      />
    )
  }
}


Was this page helpful?
0 / 5 - 0 ratings