I built a MERN project where the component FrindListWidget is called under 2 conditions.
user.friends will be updated. Each Friend also contains a , which will add or remove Friend.
Apparently, everything was working fine until I checked the Network tab in Chrome Developer Tools. I detected that friends was called an infinite number of times. To make it clear, I wrote console.log("friends",friends);. Yes, it has been recorded numerous times.
I share the following code:
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 is just an axios method:
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${token}` },
});
I tried removing the dependency in the useEffect hook:
useEffect(() => {
getFriends();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
However, it only renders once. It will not show updates via at runtime. I have to reload the window to see the update.
I assume you are calling the getFriends() function which updates the list of users you injected in useEffect, therefore, making useEffect update itself infinitely, try to make your useEffect dependent on another value.
useEffect(() => { getFriends(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [userId]);For this case, I personally use react-query and use the enabled attribute to decide when to call the API again, however, there is something seriously wrong with your logic and I can't understand it, if you are able to create one using a platform like CodeSandBox Minimum reproducible example of the problem so we can better help you.