UseEffect触发的无限API调用
P粉501683874
P粉501683874 2023-09-20 20:50:56
0
1
547

我构建了一个 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粉501683874
P粉501683874

全部回复(1)
P粉156532706

我假设你正在调用getFriends()函数,该函数会更新你在useEffect中注入的用户列表,因此,使得useEffect无限次更新自身,尝试让你的useEffect依赖于另一个值。

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

对于这种情况,我个人使用react-query,并使用enabled属性来决定何时再次调用API,然而,你的逻辑存在严重问题,我无法理解它,如果你能够使用CodeSandBox等平台创建一个最小可复现的问题示例,我们可以更好地帮助你。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板