1

when I added eventList into my useEffect in an array like this:

  const getEvents = async () => {
    const res = await axios.get(`/api/v1/events/event/${teamId}`);

    setEventList(res.data.Events);
  };

  useEffect(() => {
    getEvents();
  }, [eventList]);

It just keep fetching data non stop

but if I don't put eventList in there my page just fetch it one time and when I click to another component is will gone

Added Component:

Calendar.js:

const Calendar = (props) => {
  const { teamId } = props;
  const events = [];
  const [date, setDate] = useState(new Date());
  const [eventList, setEventList] = useState([]);
  const [expanded, setExpanded] = useState("");

  const getEvents = async () => {
    const res = await axios.get(`/api/v1/events/event/${teamId}`);

    setEventList(res.data.Events);
  };

  useEffect(() => {
    getEvents();
  }, []);

  const handleChangeAccordion = (panel) => (event, newExpanded) => {
    setExpanded(newExpanded ? panel : false);
  };

  const handleChangeCalendar = (value) => {
    const currentDate = moment(value).format("YYYY-MM-DD");
    setDate(currentDate);
    const currentEvents = events.find((event) =>
      moment(currentDate).isSame(event.date, "day")
    );
    setEventList(currentEvents ? currentEvents.events : []);
  };

  const [showCalendarCard, setShowCalendarCard] = useState(false);

  const addEvent = () => {
    setShowCalendarCard(true);
  };

  return (
    <div className="calendar-tab">
      <div className="event-view-container">
        <div className="event-date">
          <p className="event-date-monthday">{moment(date).format("D")}</p>
          <p className="event-date-weekday">{moment(date).format("dddd")}</p>
        </div>
        <div className="event-list">
          {eventList.map((event, index) => (
            <div>
              <Accordion
                key={`event-${index}`}
                square
                expanded={expanded === `event${index + 1}`}
                onChange={handleChangeAccordion(`event${index + 1}`)}
              >
                <AccordionSummary>
                  <div className="event-list-item-header">
                    <span className="timestart">
                      {moment(event.timestart, "HH:mm:ss").format("h:mm A")}
                    </span>
                    <span className="dash">-</span>
                    <span className="timeend">
                      {moment(event.timeend, "HH:mm:ss").format("h:mm A")}
                    </span>
                    <span className="title">{event.title}</span>
                  </div>
                </AccordionSummary>
              </Accordion>
              <div className="event-list-item-content">
                <div className="header">
                  <span className="announcements">Announcements</span>
                  <div className="plus">
                    <ControlPoint />
                  </div>
                </div>
                <div className="content">{event.description}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
      <div className="calendar-view-container">
        <div className="event-calendar-container">
          {!showCalendarCard ? (
            <div>
              <EventCalendar
                className="event-calendar"
                formatShortWeekday={(locale, date) =>
                  moment(date).format("dd").charAt(0)
                }
                tileClassName={({ date }) => {
                  if (events.find((x) => moment(x.date).isSame(date, "day"))) {
                    return "highlight";
                  }
                }}
                onChange={(value) => handleChangeCalendar(value)}
                nextLabel={<NavigateNext />}
                prevLabel={<NavigateBefore />}
              />
              <div className="add-event">
                <ControlPoint onClick={addEvent} />
              </div>
            </div>
          ) : (
            <CalendarCard
              setShowCalendarCard={setShowCalendarCard}
              teamId={teamId}
            />
          )}
        </div>
      </div>
    </div>
  );
};

export default Calendar;

When I click to another day in calendar it will disspear my list of events.

Here is the photo of my project:

enter image description here

nathan
  • 369
  • 2
  • 14
  • I would suggest using a timer of some sort rather than putting React into an infinite loop. – DBS Apr 23 '21 at 12:42
  • @DBS how can I do that? – nathan Apr 23 '21 at 12:43
  • There are some decent questions that cover this sort of thig, e.g. [Polling api every x seconds with react](https://stackoverflow.com/questions/46140764/polling-api-every-x-seconds-with-react) – DBS Apr 23 '21 at 12:44

2 Answers2

2

Your useEffect is depending on eventList to change and by calling that function you are changing eventList, If you want to send the request only once then this solution will do

const Calendar = (props) => {
  const { teamId } = props;
  // const events = [];
  const [date, setDate] = useState(new Date());
  const [eventList, setEventList] = useState([]);
  const [expanded, setExpanded] = useState("");

  const getEvents = async () => {
    const res = await axios.get(`/api/v1/events/event/${teamId}`);

    setEventList(res.data.Events);
  };

  useEffect(() => {
    getEvents();
  }, []);

Having an empty dependant list will only trigger the function once so change

useEffect(() => {
    getEvents();
  }, [eventList]);

To this

useEffect(() => {
    getEvents();
  }, []);
SnaccOvenFlour
  • 158
  • 3
  • 14
1

Its stuck in a loop because your useEffect callback has the side-effect changing it's own dependency (eventList).

Basically instead of resetting the event list you fetched from the API, memoize the filtered list

e.g.

const filteredEventList = useMemo(() => {
  return eventList.filter((event) =>
      moment(date).isSame(event.date, "day")
    )
}, [date, eventList])

and then use this filtered event list in your render

Andrew Gillis
  • 3,250
  • 2
  • 13
  • 15