Search code examples
javascriptreactjsuse-effectreact-state

React: How to avoid duplication in a state array


I am making MERN social media app.

I want to show all the friends of the current user in a list in SideBar.jsx .

Home.jsx (parent of Sidebar.jsx)

import React, { Component } from "react";
import { Person } from "@material-ui/icons";
import Topbar from "../../components/topbar/Topbar";
import Sidebar from "../../components/sidebar/Sidebar";
import Feed from "../../components/feed/Feed";
import Rightbar from "../../components/rightbar/Rightbar";
import "./home.css";
export default function Home() {
  return (
    <>
      <Topbar />
      <div className="homeContainer">
        <Sidebar />
        <Feed />
        <Rightbar />
      </div>
    </>
  );
}

SideBar.jsx

import "./sidebar.css";
import React, { Component, useContext, useState } from "react";
...
import { axiosInstance } from "../../config";

export default function Sidebar() {
  const { user } = useContext(AuthContext);
  const [followings, setFollowings] = useState([]);
  const followingsList = user.followings;
  useEffect(() => {
    const fetchFollowings = async () => {
      followingsList.map(async (id) => {
        try {
          const theUser = await axiosInstance.get(`/users?userId=${id}`);
          if (followings.includes(theUser.data)) {
          } else {
            setFollowings((prev) => [...prev, theUser.data]);
          }
        } catch (error) {
          console.log(error);
        }

      });
    };
    fetchFollowings();
  }, [user]);
  return (
    <div className="sidebar">
  .....
        <ul className="sidebarFriendList">
          {followings.map((u) => (
            <CloseFriend key={u._id} user={u} />
          ))}
        </ul>
      </div>
    </div>
  );
}


For example, in this case, in the state "followings", there are 2 user objects.

So, the line

 followings.map((u) => (...

should only show 2 entries.

However, the result is below.

enter image description here

As you can see, it is showing each friend twice. I tired to check if a user object already exists in followings by doing

 if (followings.includes(theUser.data)) {
          } else {
            setFollowings((prev) => [...prev, theUser.data]);
          }

But this is not working.

How can I make sure that it only shows each user once?

I want it to be like this enter image description here

Any help would be greatly appreciated. thank you


Solution

  • This is happening because it seems that your useEffect method is being fired two times (probably because you are using React.StrictMode) and you are setting the state inside the .map method (that is not good because you trigger a new render each time you call the setState).

    What I would recommend you to do, is to remove the setState from the .map method and just set the new state after you format your data. So it would be something like this:

    const newFollowings = followingsList.map(async (id) => {
      try {
        const theUser = await axiosInstance.get(`/users?userId=${id}`);
        return theUser.data;
      } catch (error) {
        console.log(error);
      }
    });
    
    setFollowings(newFollowings);
    

    Probably you would have to add a filtering to the array in case there are some errors (because on errors the mapped value would be undefined):

    .filter(data => data);