如果我在 useEffect 中添加状态,useEffect 会继续获取我的数据

Posted

技术标签:

【中文标题】如果我在 useEffect 中添加状态,useEffect 会继续获取我的数据【英文标题】:useEffect keep fetching my data if I add state in useEffect 【发布时间】:2021-04-23 12:38:25 【问题描述】:

当我在这样的数组中将 eventList 添加到我的 useEffect 中时:

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

    setEventList(res.data.Events);
  ;

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

它只是不停地获取数据

但是如果我不把 eventList 放在那里,我的页面只需获取一次,当我点击另一个组件时就会消失

添加的组件:

日历.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;

当我点击日历中的另一天时,它会显示我的事件列表。

这是我项目的照片:

【问题讨论】:

我建议使用某种计时器,而不是将 React 置于无限循环中。 @DBS 我该怎么做? 有一些体面的问题涵盖了这种事情,例如Polling api every x seconds with react 【参考方案1】:

您的 useEffect 取决于 eventList 进行更改,并且通过调用该函数您正在更改 eventList,如果您只想发送一次请求,那么这个解决方案就可以了

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();
  , []);

有一个空的依赖列表只会触发一次函数,所以改变

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

到这里

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

【讨论】:

但是如果我换成其他组件时只调用一次它就会消失 你能编辑你的问题并添加组件吗? 我刚刚编辑了它。因此,当我单击日历中的另一天时,数据将消失,当我单击返回创建日期时,它仍然消失【参考方案2】:

它卡在一个循环中,因为您的 useEffect 回调具有改变它自己的依赖关系 (eventList) 的副作用。

基本上不是重置您从 API 获取的事件列表,而是记住过滤后的列表

例如

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

然后在你的渲染中使用这个过滤的事件列表

【讨论】:

我该如何解决这个问题? 你需要更好地组织你的代码。避免在用户输入内容时点击 API。我会更详细地编辑。 更新了,看看吧。

以上是关于如果我在 useEffect 中添加状态,useEffect 会继续获取我的数据的主要内容,如果未能解决你的问题,请参考以下文章

状态在 useEffect 中没有更新,为啥?

如何使用 React Hooks 和 Context API 正确地将来自 useEffect 内部调用的多个端点的数据添加到状态对象?

useState和useEffect

我可以使用react中的useEffect挂钩从子级设置父级的状态

在useEffect中多次设置状态仅设置最后一个

React useEffect 清理函数中的依赖没有更新