1

I have this code where I am fetching data and passing it to a component. This child component then renders the data I have made it so that when the user pulls down from the top, the component will refresh but whenever I refresh for the first time only, I get the error

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 a useEffect cleanup function.

Here is the code:

function FolloweringScreens({
  data,
  screen,
  username,
  navigation,
  noMoreData,
  setLoadingMore,
  lastVisible,
  setNoMoreData,
  setLastVisible,
  setfollowingData,
  loadingMore,
  setLoading,
  currentuser,
}) {
  const [stateData, setStateData] = useState();
  const [refresh, setRefresh] = useState(false);

  useEffect(() => {
    const setState = () => setStateData(data);
    return setState();
  }, [data, refresh]);

  // Refresh
  const handleFetch = () => {
    setRefresh(true);
    const cleanup = fetchData(
      username,
      setfollowingData,
      setLoading,
      setLastVisible,
      setNoMoreData,
      setRefresh,
      screen,
      currentuser,
    );
    return cleanup;
  };

  return (
    <>
      <FlatList
        refreshing={refresh}
        onRefresh={handleFetch}
        data={stateData}
        keyExtractor={(i, index) => index.toString()}
        renderItem={({item, index}) => {
          return (
            <>
                 { Using my data here }
            </>
          );
        }}
      />
    </>
  );
}

export default FolloweringScreens;

Here is the fetchData function:

export const fetchData = (
  username,
  setfollowingData,
  setLoading,
  setLastVisible,
  setNoMoreData,
  setRefresh,
  screen,
  currentuser,
) => {
  const dataaRef = firestore().collection('usernames');
  setNoMoreData && setNoMoreData(false);

  // If in

  dataaRef // Go to whichever users clicked on data
    .doc(username.toLowerCase())
    .collection(screen) // Go to followers/following
    .orderBy('followedAt')
    .limit(6)
    .get()
    .then((snapshot) => {
      setLoading(true);
      snapshot.empty
        ? null
        : setLastVisible(
            snapshot.docs[snapshot.docs.length - 1].data().followedAt,
          );
      let promises = [];
      // 1b. For each document, return that document data
      snapshot.forEach((doc) => {
        const data = doc.data();
        promises.push(
          data.path.get().then((res) => {
            const userData = res.data();

            // Go to logged in users directory to see
            // if they are following these users in this
            // users following/followers page so we can
            // differentiate whether to display follow/unfollow button
            return dataaRef
              .doc(
                currentuser === undefined
                  ? username.toLowerCase()
                  : currentuser.toLowerCase(),
              )
              .collection('Following')
              .doc(doc.id)
              .get()
              .then((searchedDocs) => {
                return {
                  profileName: doc.id ? doc.id : null,
                  displayName: userData.displayName
                    ? userData.displayName
                    : null,
                  followerCount:
                    userData.followers !== undefined ? userData.followers : 0,
                  followingCount:
                    userData.following !== undefined ? userData.following : 0,
                  imageUrl: userData.imageUrl ? userData.imageUrl : null,
                  isFollowed: searchedDocs.exists ? true : false,
                };
              });
          }),
        );
      });
      // 1c. set All document data to followingData
      Promise.all(promises).then((res) => {
        setfollowingData(res);
        // console.log('res', res);
      });
      setLoading(false);
      setRefresh && setRefresh(false);
    });
};
Junaid Razaq
  • 241
  • 5
  • 14

1 Answers1

1

You can't do that actually. Since the function that returns from useEffect act as a clean up function. You usually clean up your back like removing event listeners and such things when a component dispose.

useEffect(() => {

  document.addEventListenter('click', () => {});

  function cleanup() {
    document.removeEventListener('click', () => {});
  };

  return cleanup;

})

This is how useEffect works. So in your case it is complaining about an state update when component is getting unmounted which is illegal in react world.

If you are trying to call it just call it.

useEffect(() => {
  const setState = () => setStateData(data);
  setState();
}, [data, refresh]);

Or a better way is to define your function outside of useEffect, and call it inside of it.

const setState = () => setStateData(data);

useEffect(() => {
  if (!data) return;
  setState();
}, [data, refresh]);
sadrzadehsina
  • 1,331
  • 13
  • 26
  • Unfortunately I am still receiving this error, but everything works, the page refreshes with the updated data, and the error only appears on the first refresh attempt. Could I ignore it? it doesn't seem to be giving any problems, just an error message, Thank you – Junaid Razaq Jan 31 '21 at 19:27
  • 1
    @JunaidRazaq where is `fetchData` in your code? I can't see what it is doing. – sadrzadehsina Jan 31 '21 at 19:28
  • 1
    Or maybe the issue is not with this part of your code. One thing you can do, you can disable. ( comment ) all useEffects and see if you still get the same error. – sadrzadehsina Jan 31 '21 at 19:30
  • In the handleFetch function. I will update the question also to show what the function actually does also – Junaid Razaq Jan 31 '21 at 19:31
  • When i comment the useEffect out, i am still receiving this error. it looks like the handleFetch function may be causing this error – Junaid Razaq Jan 31 '21 at 19:37
  • I found a fix. It is very complex but it involved you code. Thank you sir! – Junaid Razaq Jan 31 '21 at 20:19