Also James
Also James

Reputation: 21

Too many re-renders for component

I am trying to call a component that shows the details of a notification when the notification is clicked. However, I kept on getting an error of too many re-renders.

This is my Notifications code This component calls the database to get the list of notifications and then sets the first notification as the default notification clicked.

const Notification = (hospital) => {
const [users, setUsers] = useState([]);
  const [search, setSearch] = useState(null);
  const [status, setStatus] = useState(null);

    const [notifDetails, setNotification] = useState();

useEffect(async () => {
    await axios
      .get("/notifications")
      .then((res) => {
        const result = res.data;
        setUsers(result);
        setNotification(result[0]);
      })
      .catch((err) => {
        console.error(err);
      });
  }, []);
    return(
      <div className="hospital-notif-container">
         {filteredList(users, status, search).map((details, index) => {
              for (var i = 0; i < details.receiver.length; i++) {
                if (
                  (details.receiver[i].id === hospital.PK ||
                    details.receiver[i].id === "others") &&
                  details.sender.id !== hospital.PK
                ) {
                  return (
                    <div
                      className="hospital-notif-row"
                      key={index}
                      onClick={() => setNotification(details)}
                    >
                      <div className="hospital-notif-row">
                          {details.name}
                      </div>
                    </div>
                  );
                }
              }
              return null;
            })}
          </div>
          <NotificationDetails details={notifDetails} /> 
   );
}

For NotificationDetails:

This function is triggered when a notification is clicked from Notifications. The error is said to be coming from this component.

    const NotificationDetails = ({ details }) => {
  const [loading, setLoading] = useState(true);
useEffect(() => {
    if (Object.keys(details).length != 0) {
      setLoading(false);
    }
  }, [details]);
if (!loading) {
    return (
      <>
        <div className="hospital-details-container">
            <h2>{details.sender.name}</h2>
        </div>
     </>
    );
  } else {return (<div>Loading</div>);}
};

What should I do to limit the re-render? Should I change the second argument of the useEffects call? Or am I missing something in my component?

I tried calling console.log from NotificationDetails and it shows that it is infinitely rendering with the data I set in axios which is result[0]. How is this happening?

Upvotes: 0

Views: 87

Answers (1)

Giovanni Esposito
Giovanni Esposito

Reputation: 11156

Your problem should be in NotificationDetails rendering. You should write something like:

const NotificationDetails = ({ details }) => {
    const [loading, setLoading] = useState(true);
    useEffect(() => {
       if (details.length != 0) {
         setLoading(false);
       }
    }, [details]);

    return (
      <div>
       {loading && 
          <div className="hospital-details-container">
            <div className="hospital-details-header">
              <h2>{details.sender.name}</h2>
            </div>
          </div>
       }
       {!loading && 
          <div>
             <ReactBootStrap.Spinner animation="border" />
          </div>
       }
      </div>
    );
  }

With return outside the condition statement.

EDIT

Now I noted that you have an async useEffect that is an antipattern. You should modify your useEffect in this way:

 useEffect(() => {
    (async () => {
      await axios
        .get("/notifications")
        .then((res) => {
           const result = res.data;
           setUsers(result);
           setNotification(result[0]);
        })
        .catch((err) => {
           console.error(err);
        });
    })()
  }, []);

Upvotes: 1

Related Questions