React-native-pager-view: ViewPager does not re-render correctly on deleting last index of the array

Created on 22 Nov 2019  路  5Comments  路  Source: callstack/react-native-pager-view

Bug

Please excuse my English, explanation may be a little long before I actually talk about the problem (reproducible code at the end).

Currently, I have ViewPager setup with array of 4 items.

I have to delete an item(or equivalent to screen) in the array by clicking a button located at that screen, using the position returned from onPageSelected.

_onPressDelete = index => {
    let newArr = this.state.result;
    newArr.splice(index, 1);
    this.setState({result: newArr});
  };

Here is a simulation of the problem.

68726184-07e05680-0604-11ea-9bd8-91984509e810

For example, if I click the delete button in screen 2, component re-renders and next screen(screen 3) is shown as state changes. This should be the correct response. This is the next state after delete:

68726268-42e28a00-0604-11ea-9dfc-2d63263a607a

Deleting any screen from screen1 to screen 3 works without any problem since there is a screen next to the deleted screen. However problem occurs when I try to delete the last screen (screen 4). Since screen 4 is last screen and there is no screen 5 to move to, viewPager re-renders with just blank screen (with other bugs like showing deleted screen again)

This problem only occurs on ios and not on android, so I guess it is ios problem only. On Android, deleting the last index correctly falls back to the previous screen, e.g. screen 3.
Any fixes to the problem?

Environment info

React native info output:

Android Studio: 3.5 AI-191.8026.42.35.5900203
Xcode: 11.0/11A420a - /usr/bin/xcodebuild
npmPackages:
react: 16.9.0 => 16.9.0
react-native: 0.61.4 => 0.61.4
npmGlobalPackages:
react-native-cli: 2.0.1

ViewPager Library version: 3.1.0

Steps To Reproduce

  1. I have provided a code below to try. It will be much easier to understand if you try the code

2.If you press delete button in screen 5, it will show blank as it re-renders. Other screens work perfectly fine. There is no problem on Android.
...

Reproducible sample code

import React, {Component} from 'react';
import {
  StyleSheet,
  View,
  Text,
  Dimensions,
  Button,
} from 'react-native';
import ViewPager from '@react-native-community/viewpager';

class App extends Component {
  state = {
    result: ['screen 1', 'screen 2', 'screen 3', 'screen 4', 'screen 5'],
  };

  _onPressDelete = index => {
    let newArr = this.state.result;
    newArr.splice(index, 1);
    this.setState({result: newArr});
  };

  render() {
    return (
      <ViewPager style={styles.container} initialPage={0} showPageIndicator>
        {this.state.result.map((item, index) => {
          return (
            <View style={styles.pageItem} key={item}>
              <Text style={{fontSize: 20}}>{item}</Text>
              <Button
                title="delete"
                onPress={() => {
                  this._onPressDelete(index);
                }}
              />
            </View>
          );
        })}
      </ViewPager>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  pageItem: {
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').height,
    backgroundColor: 'lightgrey',
    justifyContent: 'center',
  },
});

export default App;

bug ios

Most helpful comment

I am having the same issue as mentioned above.
Is this bug solved or still in any progress?
Is there anything I can help with?

All 5 comments

This might be a bit related to https://github.com/react-native-community/react-native-viewpager/issues/104.

Basically hard to achieve only in the JS side and we still need to probably find a solution inside the library.

This might be a bit related to #104.

Basically hard to achieve only in the JS side and we still need to probably find a solution inside the library.

Thanks.
Though do you know why it works fine On Android?

I am having the same issue as mentioned above.
Is this bug solved or still in any progress?
Is there anything I can help with?

I am having the same issue as mentioned above.
Is this bug solved or still in any progress?
Is there anything I can help with?

There has trick solution but not the best solution which I found could work.

{this.state.showViewPager && (
  <ViewPager style={{ height: 250 }} initialPage={0} showPageIndicator>
    {images && images.map((image, index) => {
      return (
        <View key={index}>
          <Text>{image}</Text>
        </View>
      )
    })}
  </ViewPager>
)}
const { images } = this.state
images.splice(index, 1)
this.setState({ showViewPager: false })
this.setState({ showViewPager: images.length > 0, images })

I just add the showViewPager flag, and whenever I increase or decrease screen length, I will also alter showViewPager in order re-render the ViewPager component

I am having the same issue as mentioned above.
Is this bug solved or still in any progress?
Is there anything I can help with?

Hey @rakeshvora2007,
I would really appreciate, if you can find some time and take a look on it.

I can see from @panda6412 's snippet, that VP need to be unmount and then mount again.

If you need any guidance, how to fix it, please let me know here in comments :D

Thanks.
Though do you know why it works fine On Android?

Because Android has different implementation than iOS. Both are purely native and can work differently. Of course on the end the effect is the same. JavaScript is unifying both platform into one common api.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

supermaverickws picture supermaverickws  路  8Comments

ferrannp picture ferrannp  路  10Comments

ferrannp picture ferrannp  路  8Comments

olhapi picture olhapi  路  4Comments

hengkx picture hengkx  路  8Comments