Flatlist Sometimes Capped at 10 Items Bug

20 Views Asked by At

I've really been struggling with one of my FlatLists. Sometimes (seemingly at random) my FlatList will only show the first 10 items and will not display more items when I scroll to the bottom. I have no idea what is triggering this, it just happens sometimes when using my app.

I am aware that the default number of initial items loaded is 10 and that's why the first 10 are showing. I don't want to just increase this as that defeats the whole point of the FlatList to efficiently display the dataset. I've verified that more than 10 users are being supplied to the FlatList even when this issue happens. This is has been driving me crazy, if anyone can point out any problems in my component I would very much appreciate it. I have many other FlatLists in my app which don't have this problem ever.

Here is my code:

import React, {useState, useEffect, useMemo, useCallback} from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Image,
  FlatList,
  RefreshControl,
} from 'react-native';
import styles from './UserGalleryStyles'; // StyleSheet file
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome';
import {faCheck} from '@fortawesome/free-solid-svg-icons';
import Config from 'react-native-config';

const UserGallery = ({
  users2,
  navigation2,
  userId2,
  selectedCategoryName2,
  setUpdateFilters,
}) => {
  // Render each user
  const [localUsers, setLocalUsers] = useState(users2);
  const [refreshing, setRefreshing] = useState(false);
  const apiUrl = Config.REACT_APP_BACKEND_URL;
  useEffect(() => {
    setLocalUsers(users2);
  }, [users2]);

  const onRefresh = () => {
    setRefreshing(true);
    setUpdateFilters(prevFilters => prevFilters + 1);
    // Add any other logic you need to perform during refresh
    // After the data is fetched or updated, set refreshing to false
    setRefreshing(false);
  };

  const handleSendFriendRequest = async profileId => {
    const updatedUsers = localUsers.map(user => {
      if (user.user_id === profileId) {
        return {
          ...user,
          friend_request: true, // Update the user_rating.
        };
      }
      return user; // Leave all other products unchanged.
    });

    // Update the state with the modified products array.
    setLocalUsers(updatedUsers);

    // Define the payload
    const payload = {
      user_id: userId2,
      profile_id: profileId,
    };

    // Send the POST request
    try {
      const response = await fetch(`${apiUrl}/send_friend_request`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
      });

      // Check if the POST request was successful
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      // You may want to do something with the response here
      const data = await response.json();

      // Optionally, you could confirm the change happened on the backend
      // and update the state again if necessary
    } catch (error) {
      console.error('Failed to send friend request:', error);
    }
  };

  const handleFollow = async profileId => {
    // Update the local state first to reflect the change optimistically
    const updatedUsers = localUsers.map(user => {
      if (user.user_id === profileId) {
        return {
          ...user,
          is_following: true, // Update the user_rating.
        };
      }
      return user; // Leave all other products unchanged.
    });

    // Update the state with the modified products array.
    setLocalUsers(updatedUsers);

    // Define the payload
    const payload = {
      user_id: userId2,
      profile_id: profileId,
      relationship: 'Following',
    };

    // Send the POST request
    try {
      const response = await fetch(`${apiUrl}/add_usertag`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
      });

      // Check if the POST request was successful
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      // You may want to do something with the response here
      const data = await response.json();

      // Optionally, you could confirm the change happened on the backend
      // and update the state again if necessary
    } catch (error) {
      console.error('Failed to send follow', error);
    }
  };

  const renderItem = ({item: user}) => (
    <View style={styles.galleryCard}>
      <View style={styles.cardMain}>
        <View style={styles.cardLeft}>
          <TouchableOpacity
            onPress={() =>
              navigation2.navigate('UserProfile', {
                profile_id: user.user_id,
              })
            }>
            <Image source={{uri: user.photo_url}} style={styles.cardImage} />
          </TouchableOpacity>
        </View>

        <View style={styles.cardMiddle}>
          <Text style={styles.userName}>@{user.username}</Text>
          <Text style={styles.userInfo}>
            {/*{user.user_type} User
              {'\n'} */}
            Ratings: {user.rating_count}{' '}
            {user.common_ratings > 0 ? `(${user.common_ratings} Mutual)` : ''}
          </Text>
        </View>

        <View style={styles.cardRight}>
          <View>
            {user.similarity > 0 ? (
              <Text style={styles.similarity}>{user.similarity}%</Text>
            ) : (
              <Text style={styles.similarity}>?</Text>
            )}
            {selectedCategoryName2 !== 'None' &&
              selectedCategoryName2 != null && (
                <Text style={styles.text}>{selectedCategoryName2}</Text>
              )}
            <Text style={styles.text}>Similarity</Text>
          </View>
        </View>
      </View>

      <View style={styles.cardFooter}>
        {userId2 && (
          <View style={styles.cardRelations}>
            <View style={styles.followStatus}>
              {user.is_following ? (
                <View style={styles.friends_container}>
                  <Text style={styles.friends}>Following</Text>
                  <FontAwesomeIcon icon={faCheck} style={styles.tick} />
                </View>
              ) : (
                <TouchableOpacity
                  style={styles.follow}
                  onPress={() => handleFollow(user.user_id)}>
                  <Text style={styles.followText}>Follow</Text>
                </TouchableOpacity>
              )}
            </View>

            <View style={styles.friendStatus}>
              {user.is_friend ? (
                <View style={styles.friends_container}>
                  <Text style={styles.friends}>Friends</Text>
                  <FontAwesomeIcon icon={faCheck} style={styles.tick} />
                </View>
              ) : user.friend_request ? (
                <Text style={styles.friendRequestSent}>Request Sent</Text>
              ) : (
                <TouchableOpacity
                  style={styles.friendRequest}
                  onPress={() => handleSendFriendRequest(user.user_id)}>
                  <Text style={styles.friendRequestText}>Add Friend</Text>
                </TouchableOpacity>
              )}
            </View>
          </View>
        )}
      </View>
    </View>
  );

  return (
    <FlatList
      data={localUsers}
      renderItem={renderItem}
      keyExtractor={item => item.user_id.toString()}
      contentContainerStyle={styles.gallery}
      refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
      }
    />
  );
};

export default UserGallery;

And it being called like this in my screen:

<UserGallery users2={users} userId2={userId} navigation2={navigation} selectedCategoryName2={selectedCategoryName} setUpdateFilters={setUpdateFilters} />

Want a FlatList which works as normal showing more items as you scroll down.

1

There are 1 best solutions below

1
Elvin On

I understand from the code that there might be an issue with the refreshControl and the onRefresh method. Please check carefully; you are only updating setRefreshing to true and false, which doesn't seem to make sense.