首頁  >  問答  >  主體

UseEffect觸發的無限API調用

我建立了一個 MERN 項目,其中元件 FrindListWidget 在 2 個條件下被呼叫。

  1. 如果是使用者自己的朋友清單,則會渲染該小元件,且 Redux user.friends 中的狀態也會更新。
  2. 如果是其他用戶,則僅渲染小工具。 Redux 狀態不會更新。

每個 Friend 還包含一個 ,它將新增或刪除 Friend。 顯然,在我檢查 Chrome 開發者工具中的網頁標籤之前,一切都運作得很好。我偵測到 friends 被無限次呼叫。為了說清楚,我寫了console.log("friends",friends);。是的,它被記錄了無數次。 我分享以下程式碼:

FriendListWidget.jsx

#
//other mui imports
import { WidgetWrapper } from "../../../components/StyledComponent/WidgetWrapper";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setFriends as setUsersFriends } from "../../../Redux/Slices/authSlice";
import { userRequest } from "../../../requestMethod";

import Friend from "../../../components/Friend";

const FriendListWidget = ({ userId }) => {
  const dispatch = useDispatch();
  const { palette } = useTheme();
  const [friends, setFriends] = useState([]);
  const user = useSelector((state) => state.user);

  const getFriends = async () => {
    const res = await userRequest.get(`/users/${userId}/friends`);
    const data = await res.data;
    if (user._id === userId) {
      dispatch(setUsersFriends({ friends: data }));
      setFriends(data);
    } else {
      setFriends(data);
    }
  };

  useEffect(() => {
    getFriends();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user, userId]);

  console.log("friends", friends); //This is being logged for infinite times

  return (
    <WidgetWrapper>
      <Typography
        color={palette.neutral.dark}
        variant="h5"
        fontWeight="500"
        sx={{ mb: "1.5rem" }}
      >
        Friend List
      </Typography>
      <Box display="flex" flexDirection="column" gap="1.5rem">
        {friends.map((friend) => (
          <Friend
            key={friend._id}
            friendId={friend._id}
            name={`${friend.firstName} ${friend.lastName}`}
            subtitle={friend.occupation}
            userPicturePath={friend.picturePath}
          />
        ))}
      </Box>
    </WidgetWrapper>
  );
};

export default FriendListWidget;

Friend.jsx

//other mui imports
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { userRequest } from "../../requestMethod";
import { setFriends } from "../../Redux/Slices/authSlice";
import { FlexBetween } from "../StyledComponent/FlexBetween";
import UserImage from "../StyledComponent/UserImage";

const Friend = ({ friendId, name, location, userPicturePath }) => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const { _id } = useSelector((state) => state.user);
  const friends = useSelector((state) => state.user.friends);

  const { palette } = useTheme();
  const primaryLight = palette.primary.light;
  const primaryDark = palette.primary.dark;
  const main = palette.neutral.main;
  const medium = palette.neutral.medium;

  const isFriend = friends.find((friend) => friend._id === friendId);
  const isUser = friendId === _id;

  const patchFriend = async () => {
    const res = await userRequest.patch(`/users/${_id}/${friendId}`);
    const data = await res.data;
    dispatch(setFriends({ friends: data }));
  };

  return (
    <FlexBetween>
      <FlexBetween gap="1rem">
        <UserImage image={userPicturePath} size="55px" />
        <Box
          onClick={() => {
            navigate(`/profile/${friendId}`);
            navigate(0);
          }}
        >
          <Typography
            color={main}
            variant="h5"
            fontWeight="500"
            sx={{
              "&:hover": {
                color: palette.primary.light,
                cursor: "pointer",
              },
            }}
          >
            {name}
          </Typography>
          <Typography color={medium} fontSize="0.75rem">
            {location}
          </Typography>
        </Box>
      </FlexBetween>
      {!isUser && (
        <IconButton
          onClick={() => patchFriend()}
          sx={{ backgroundColor: primaryLight, p: "0.6rem" }}
        >
          {isFriend ? (
            <PersonRemoveOutlined sx={{ color: primaryDark }} />
          ) : (
            <PersonAddOutlined sx={{ color: primaryDark }} />
          )}
        </IconButton>
      )}
    </FlexBetween>
  );
};

export default Friend;

userRequest 只是一個 axios 方法:

export const userRequest = axios.create({
  baseURL: BASE_URL,
  headers: { token: `Bearer ${token}` },
});

我嘗試刪除 useEffect 掛鉤中的依賴項:

useEffect(() => {
    getFriends();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

但是,它只渲染一次。它不會在運行時透過 顯示更新。我必須重新加載視窗才能看到更新。

P粉501683874P粉501683874417 天前511

全部回覆(1)我來回復

  • P粉156532706

    P粉1565327062023-09-21 09:41:39

    我假設你正在調用getFriends()函數,該函數會更新你在useEffect中註入的用戶列表,因此,使得useEffect無限次更新自身,嘗試讓你的useEffect依賴於另一個值。

    useEffect(() => {
        getFriends();
        // eslint-disable-next-line react-hooks/exhaustive-deps
      }, [userId]);

    對於這種情況,我個人使用react-query,並使用enabled屬性來決定何時再次呼叫API,然而,你的邏輯存在嚴重問題,我無法理解它,如果你能夠使用CodeSandBox等平台創建一個最小可復現的問題範例,我們可以更好地幫助你。

    回覆
    0
  • 取消回覆