Unable to render data to FlatList on Scroll down using Http POST request

  1. SDK Version: 38
  2. Platforms(Android/iOS/web/all): Android

I want to render a list of items in a ReactNative FlatList, initially I am loading 15 items and then load more when user scrolls down. I am using FlatList’s onEndReached prop to get new items on scroll. I am consuming an api with POST method, which takes an object containing pageNumber, pageSize etc., as input and returns an object { success: true, message: 'success.', data: [ items : [...] ] } containing list items.

To achieve this I am using apisauce npm package and written a custom hook(useSearch.js) which handles forming api request object and then invoke api and and get items.

I am getting below error when I scroll down to the screen. When the component loads first time I am not getting any error but when I scroll I am getting below error. After trying some time I realized that same code is working for any other Http GET requests, but when I use Http POST method its not working.

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function, 
    in App (created by ExpoRoot)
    in RCTView (at NativeAppearance.tsx:4)
    in FallbackAppearanceProvider (at src/index.tsx:70)
    in AppearanceProvider (created by ExpoRoot)
    in RootErrorBoundary (created by ExpoRoot)
    in ExpoRoot (at renderApplication.js:45)
    in RCTView (at AppContainer.js:109)
    in RCTView (at AppContainer.js:135)
    in AppContainer (at renderApplication.js:39)
TypeError: undefined is not an object (evaluating 'item.listingId.toString')

Below is the code I am using

client.js

import { create } from "apisauce";

const apiClient = create({
  baseURL: 'http://localhost:9000',
});

export default apiClient;

useSearch.js (Custom Hook)

const useSearch = () => {
  const searchList = { pageNumber: 1, pageSize: 15, sortField: "createddate", sortOrder: "desc", isActive: true};

  const [items, setItems] = useState([]);
  const [error, setError] = useState(false);
  const [pageNumber, setPageNumber] = useState(1);
  const [loading, setLoading] = useState(false);

  const endpoint = "/listings";

  const getItems = async (categoryId) => {
    setLoading(true);
    setPageNumber((prevPageNumber) => prevPageNumber + 1);

    const response = await apiClient.post(`${endpoint}/search`, {
      ...searchList,
      pageNumber,
      categoryId,
    });

    setLoading(false);
    if (!response.ok) {
      if (response.data && response.data.message) return setError(true);
      else return setError(true);
    }

    if (items && items.length > 0)
      setItems([...items, response.data?.data?.items]);
    else setItems(response.data?.data?.items);

    return response;
  };

  return {error, getItems, items, loading };
};

ListingsScreen.js (Component)

const ListingsScreen = ({ route }) => {
  const categoryId = route.params;

  const { items, getItems, loading } = useSearch();

  useEffect(() => {
    getItems(categoryId);
  }, []);

  return (
    <>
      <ActivityIndicator visible={loading} />
      <Screen style={styles.screen}>
        <FlatList
          showsVerticalScrollIndicator={false}
          data={items}
          keyExtractor={(item) => item.listingId.toString()}
          renderItem={({ item }) => (
            <CustomListItem onPress={() => console.log("On Press Item")} title={item.name} subTitle={item.category} />
          )}
          onEndReached={() => getItems(categoryId)}
          onEndReachedThreshold={0.5}
        />
      </Screen>
    </>
  );
};

How to solve this problem? Any help is appreciated.

Totally guessing - I’m curious if onEndReached gets triggered more than once and ensuring only one request happens at any given time might fix the issue. When you use “GET”, I’m curious if the multiple requests get de-duped, but when you’re using “POST”, maybe they don’t.

The error message suggests that you’ve kicked something off that then later tries to update the state at a stale moment in time. So you kicked off a side effect or something in useEffect and you’re somehow not cleaning it up properly.