无法对未安装的组件 useEffect 错误执行 React 状态更新

Can't perform a React state update on an unmounted component useEffect error

我有这段代码,我在其中获取数据并将其传递给组件。然后这个子组件呈现我制作的数据,这样当用户从顶部下拉时,组件将刷新但是每当我刷新 first time only 时,我都会收到错误

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.

代码如下:

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;

这里是 fetchData 函数:

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

实际上你不能那样做。由于 useEffect 中的 returns 函数充当清理函数。你通常会清理你的背部,比如在处理组件时删除事件监听器和类似的东西。

useEffect(() => {

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

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

  return cleanup;

})

这就是 useEffect 的工作原理。因此,在您的情况下,当组件被卸载时,它会抱怨状态更新,这在 React 世界中是非法的。

如果你想调用它就调用它。

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

或者更好的方法是在 useEffect 之外定义您的函数,然后在其中调用它。

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

useEffect(() => {
  if (!data) return;
  setState();
}, [data, refresh]);