React-native-swiper: onIndexChanged is not triggered if state is set after fetch

Created on 22 Dec 2017  路  6Comments  路  Source: leecade/react-native-swiper

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

Most helpful comment

u can try this way

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

All 6 comments

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();
    }
  }
}

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...

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

Thanks Bro!!!!

u can try this way

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

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kliuj picture kliuj  路  3Comments

nicolabortignon picture nicolabortignon  路  3Comments

AndrewSouthpaw picture AndrewSouthpaw  路  3Comments

agzuniverse picture agzuniverse  路  3Comments

kylehagler picture kylehagler  路  3Comments