react-native-swiper icon indicating copy to clipboard operation
react-native-swiper copied to clipboard

onIndexChanged is not triggered if state is set after fetch

Open ozmaat opened this issue 7 years ago • 7 comments

Which OS ?

Android

Version

Which versions are you using:

  • react-native-swiper v? 1.5.13
  • react-native v0.?.? 0.51

Expected behaviour

When data is fetched from remote network, onIndexChanged to work.

Actual behaviour

onIndexChanged is not triggered

Steps to reproduce

Below is a sample screen code.

import React, { Component } from "react";
import {
  View,
  Text,
  ImageBackground,
  StyleSheet,
  Dimensions
} from "react-native";
import Swiper from "react-native-swiper";

export default class TestSwiper extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataMovies: []
    };
  }

  componentDidMount() {
    this.getJsonData().then(dataMovies => {
      this.setState({
        dataMovies: dataMovies
      });
    });
  }
  getJsonData = () => {
    return new Promise((resolve, reject) => {
      fetch("https://facebook.github.io/react-native/movies.json")
        .then(response => response.json())
        .then(responseJson => {
          resolve(responseJson.movies);
        })
        .catch(error => {
          console.error(error);
        });
    });
  };

  swiperIndexChanged = index => {
    console.log("swiperIndexChanged", "index", index);
  };

  onScrollEnd = (e, state) => {
    console.log("Index is:", state.index);
  };

  renderMovie = () => {
    let movieView: any;

    movieView = this.state.dataMovies.map((item, key) => {
      return (
        <View key={key}>
          <Text>{item.title}</Text>
        </View>
      );
    });

    return movieView;
  };

  render() {
    return [
      <View style={{ flex: 1, justifyContent: "space-between" }} key="mainView">
        <Swiper
          loadMinimal={false}
          style={{ flex: 1, justifyContent: "space-between" }}
          onIndexChanged={index => {
            console.log("onindexchanged");
            this.swiperIndexChanged(index);
          }}
          loop={false}
          showButtons={true}
          onMomentumScrollEnd={this.onScrollEnd}
        >
          {this.renderMovie()}
        </Swiper>
      </View>
    ];
  }
}

Swiper functions correctly but onIndexChanged is not triggered.

If we change the componentDidMount function as follow, and just set the "dataMovies" state directly, the onIndexChanged is triggered.

componentDidMount() {
       this.setState({
      dataMovies: MoviesData.movies
    });
    
  }

I am not sure if this is caused by swiper or it is something about setting the state after the fetch call.

Any comments on what could be cause of index change not working in the first case

Thank you

ozmaat avatar Dec 22 '17 17:12 ozmaat

Not sure why swiper functioned as it should except the onIndexChanged but it works when you postpone the rendering till the data is ready.

Working code is below if anyone else experience the same problem.

import React, { Component } from "react";
import {
  View,
  Text,
  ImageBackground,
  StyleSheet,
  Dimensions
} from "react-native";
import Swiper from "react-native-swiper";
import MoviesData from "./movies.json";

export default class TestSwiper extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataMovies: [],
      loadData: false
    };
  }

  componentDidMount() {
    /*    this.setState({
      dataMovies: MoviesData.movies
    });
    */
    this.getJsonData().then(dataMovies => {
      /*this.setState({
        dataMovies: dataMovies
      });*/
    });
  }
  getJsonData = () => {
    return new Promise((resolve, reject) => {
      fetch("https://facebook.github.io/react-native/movies.json")
        .then(response => response.json())
        .then(responseJson => {
          this.setState({
            dataMovies: responseJson.movies,
            loadData: true
          });
          resolve(responseJson.movies);
        })
        .catch(error => {
          console.error(error);
        });
    });
  };

  swiperIndexChanged = index => {
    console.log("swiperIndexChanged", "index", index);
  };

  onScrollEnd = (e, state) => {
    console.log("Index is:", state.index);
  };

  renderMovie = () => {
    let movieView: any;

    movieView = this.state.dataMovies.map((item, key) => {
      return (
        <View key={key}>
          <Text>{item.title}</Text>
        </View>
      );
    });

    return movieView;
  };

  renderLoadingView() {
    return (
      <View>
        <Text>Loading . . .</Text>
      </View>
    );
  }

  render() {
    if (this.state.loadData) {
      return [
        <View
          style={{ flex: 1, justifyContent: "space-between" }}
          key="mainView"
        >
          <Swiper
            loadMinimal={false}
            style={{ flex: 1, justifyContent: "space-between" }}
            onIndexChanged={index => {
              console.log("onindexchanged");
              this.swiperIndexChanged(index);
            }}
            loop={false}
            showButtons={true}
            onMomentumScrollEnd={this.onScrollEnd}
          >
            {this.renderMovie()}
          </Swiper>
        </View>
      ];
    } else {
      return this.renderLoadingView();
    }
  }
}

ozmaat avatar Dec 28 '17 16:12 ozmaat

I also am experiencing this issue (I understand it may be expected behaviour) and the workaround is to render Swiper after list data is ready. Am curious to see what would happen if data was appended to list afterwards...

rayzor65 avatar Feb 09 '18 07:02 rayzor65

@ozmaat your solution worked for me ...waiting for loading data!!!...?TNX a lot

imansalhi avatar Jul 16 '18 05:07 imansalhi

Thanks Bro!!!!

VesperDev avatar Sep 11 '18 06:09 VesperDev

u can try this way

Swiper key={this.state.banners.length} /Swiper

narcissus571 avatar Sep 14 '18 08:09 narcissus571

@narcissus571 it works for me, but I still don't understand why

aoarashi1988 avatar Apr 20 '19 07:04 aoarashi1988

@narcissus571 it works. amazing

sp0re avatar Dec 06 '21 12:12 sp0re