Search code examples
react-nativeitemsflatlist

Add a button "see more" in FlatList?


I use flatList to make a list of elements. I would like to show 15 elements and then add a button "see more" to show the next 15 etc. I was about tu use this tutorial : https://aboutreact.com/react-native-flatlist-pagination-to-load-more-data-dynamically-infinite-list/ But I don't need to use fetch, I already have set up the data (state.listData) and in fact, I'm a little lost on how to adapt it...

I thought that maybe anyone could help me a little. Thanks a lot

   this.state = {
      selectedId: '',
      setSelectedId:'',
      listData:''
    }
  };


  renderItem = ({ item }) => {
    const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";

    return (
      <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
        <Item
          item={item}
          onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
          style={{ backgroundColor }}
        />
        <Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
      </View>
    );
  };

  initListData = async () => {
    let list = await getFlights(0);

    if (list) {
      this.setState({
        listData: list
      });
    }
  };

render() {
    return (
            <SafeAreaView style={styles.container}>
              <FlatList
                data={this.state.listData}
                renderItem={this.renderItem}
                maxToRenderPerBatch={15}
                keyExtractor={(item) => item.id}
                extraData={this.selectedId}
              />
              <TouchableOpacity
                style={styles.touchable2}
                onPress={() => this.props.navigation.goBack()}
              >
                <View style={styles.view2}>
                  <Text style={styles.textimg2}>
                    {i18n.t("tripsform.action.back")}
                  </Text>
                </View>
                <Image
                  source={require("../../assets/images/btn-background.png")}
                  style={styles.tripsimg2}
                />
              </TouchableOpacity>
            </SafeAreaView>
    );
  };
}

I just tried this thanks to @Pramod 's answer :

const Item = ({ item, onPress, style }) => (
  <TouchableOpacity onPress={onPress} style={[styles.flightsListitem, style]}>
    <Text style={styles.h4}>{item.id}</Text>
  </TouchableOpacity>
);

export default class FlightsList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedId: '',
      setSelectedId:'',
      listData:'',
      page:1,
      perPage:2,
      loadMoreVisible:true,
      displayArray:[]
    }
  };


  renderItem = ({ item }) => {
    const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";

    return (
      <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
        <Item
          item={item}
          onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
          style={{ backgroundColor }}
        />
        <Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
      </View>
    );
  };

  initListData = async () => {
    let list = await getFlights(0);

    if (list) {
      this.setState({
        listData: list
      });
    }
  };

  componentDidMount(){
      this.setNewData()
      // console.log(tempArray)
    }

    setNewData(){
      var tempArray=[]
      if(this.state.listData.length == this.state.displayArray.length){
        this.setState({
          loadMoreVisible:false
        })
      }else{
         for(var i=0; i<(this.state.page*this.state.perPage); i++){
        tempArray.push(this.state.listData)
        }
        this.setState({
          displayArray: tempArray,
          loadMoreVisible:true
        })
      }
    }

  loadMore(){
    this.setState({
      page: this.state.page+1
    },()=>{
      this.setNewData()
    })
  }

  async UNSAFE_componentWillMount() {
    this.initListData();
  }

  render() {
    return (
      <ImageBackground
        source={require("../../assets/images/background.jpg")}
        style={styles.backgroundImage}
      >
        <Header
          backgroundImage={require("../../assets/images/bg-header.png")}
          backgroundImageStyle={{
            resizeMode: "stretch",
          }}
          centerComponent={{
            text: i18n.t("mytrips.title"),
            style: styles.headerComponentStyle,
          }}
          containerStyle={[styles.headerContainerStyle, { marginBottom: 0 }]}
          statusBarProps={{ barStyle: "light-content" }}
        />
          <SafeAreaView style={styles.container}>
              <FlatList
                data={this.state.displayArray}
                renderItem={this.renderItem}
                keyExtractor={(item) => item.id}
                extraData={this.selectedId}
              />
            {this.state.loadMoreVisible == true?
                <Button style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}}
                        title = 'load more'
                        onPress={()=>{this.loadMore()}}>
                </Button>:null}
              <TouchableOpacity
                style={styles.touchable2}
                onPress={() => this.props.navigation.goBack()}
              >
                <View style={styles.view2}>
                  <Text style={styles.textimg2}>
                    {i18n.t("tripsform.action.back")}
                  </Text>
                </View>
                <Image
                  source={require("../../assets/images/btn-background.png")}
                  style={styles.tripsimg2}
                />
              </TouchableOpacity>
            </SafeAreaView>
      </ImageBackground>
    );
  };
}

the flatlist is not displayed : I get : enter image description here


Solution

  • You can user pagination method with per page limit so that you can have granular control

    1. Load the array per page when component mount
    2. On every click increase the per page and based on per page update data of your flat list
    3. And also put a flag which will check when the data has ended which will help to hide the load more button when data ends

    Working example: https://snack.expo.io/@msbot01/suspicious-orange

     import React, { Component } from 'react';
    import {
      StyleSheet,
      Text,
      View,
      SafeAreaView,
      SectionList,
      Switch,
      FlatList
    } from 'react-native';
    import Constants from 'expo-constants';
    import Icon from 'react-native-vector-icons/FontAwesome';
    
    import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
    
    // or any pure javascript modules available in npm
    import { Card } from 'react-native-paper';
     
    
    export default class App extends Component<Props> {
      constructor(props) {
        super(props);
        this.state = {
          page:1,
          perPage:2,
          loadMoreVisible:true,
          DATA: [{
              id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
              title: 'First Item',
            },
            {
              id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
              title: 'Second Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29d72',
              title: 'Third Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29d72',
              title: 'fourth Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29d72',
              title: 'fifth Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29sd72',
              title: 'sixth Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29dr72',
              title: 'seventh Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29d7w2',
              title: 'Eight Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-145571e29ad72',
              title: 'Nineth Item',
            },
            {
              id: '58694a0f-3da1-471f-bd96-14557d1e29d72',
              title: 'Tenth Item',
            }],
        displayArray:[]
      } 
     
      }
    
      componentDidMount(){
        
        this.setNewData()
        // console.log(tempArray) 
      }
    
      setNewData(){ 
        var tempArray=[]
        if(this.state.DATA.length == this.state.displayArray.length){
          this.setState({
            loadMoreVisible:false
          })
        }else{
           for(var i=0; i<(this.state.page*this.state.perPage); i++){
          tempArray.push(this.state.DATA[i])
          }
          this.setState({
            displayArray: tempArray,
            loadMoreVisible:true
          })
        }
    
       
      }
    
      loadMore(){
        this.setState({
          page: this.state.page+1
        },()=>{
          this.setNewData()
        })
      }
      
    
      render() {
        return (
          <View style={{ flex: 1 }}>
            <FlatList
            data={this.state.displayArray}
            renderItem={({item})=> 
              <View style={{flexDirection:'row'}}>
                <Text style={{fontSize:20}}>{item.title} </Text>
              </View>
            }
            keyExtractor={item => item.id}
          />
          {this.state.loadMoreVisible == true?
    
          
          <View style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}} onClick={()=>{this.loadMore()}}>Load more</View>:null
          }
          </View>
        );
      }
    }