交集oberserver api / useEffect挂钩两次触发回调的问题

时间:2020-05-23 06:16:09

标签: reactjs use-effect intersection-observer

我不确定为什么,但是我所做的事情导致我的intersectionObserver实例中的回调触发两次,而该触发仅触发一次。 任何关于为什么这样做的见解将不胜感激。

在此组件中发生的其他事情中,我试图通过在useEffect()挂钩内的我的观察者实例上调用observe方法,来设置insersectionObserver来观察我称为底边界的元素。这工作正常,只是观察者触发了我的回调两次。我已经尝试将观察者添加到依赖数组,并且尝试将getEvents添加到依赖数组,但是我只是一个无限循环,而不是双重攻击。

import React, { useState, useEffect, useReducer } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CreatePromo from './components/promo/CreatePromo';
import MainStyle from './components/MainStyle';
import Home from './components/Home';
import SearchEvents from './components/SearchEvents';
import Social from './components/Social';
import SimpleExample from './components/EventLocationMap';
import PromoState from './components/context/PromoContext/PromoState';
import './tailwind.generated.css';
import 'react-quill/dist/quill.snow.css';
import './App.css';
// @TODO start using context api for global state management ASAP.

const App = () => {
  //set initial createPromo widget state.
  const [allEvents, setAllEvents] = useState([]);
  const [promoState, setPromoState] = useState({
    name: '',
    type: '',
    startDate: '',
    startTime: '',
    endDate: '',
    endTime: '',
    address: '',
    city: '',
    state: '',
    postal: '',
    description: '',
    pictures: '',
    files: null,
  });

  // options for the IntersectionObserver constructor below
  let options = {
    root: null,
    rootMargin: '0px',
    threshold: 1.0,
  };

  let eventsToShow = 0;

  // instantiate intersection observer.
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      console.log(entry);
      console.log(entry.isIntersecting);
    });
    eventsToShow += 4;
    console.log('trigger');
    getEvents(eventsToShow);
  }, options);

  //defines our backend api call to get events
  const getEvents = async (numberOfEvents) => {
    try {
      const events = await fetch(
        `http://localhost:3001/api/events/${numberOfEvents}`
      );
      const newData = await events.json();
      setAllEvents([...allEvents, ...newData]);
      return newData;
    } catch (error) {
      console.log(error);
    }
  };

  //wrapper function to add a new event to allEvents
  const handleSetAllEvents = (newEvent) => {
    setAllEvents([...allEvents, newEvent]);
  };

  //wrapper function for updating controlled form state
  const handlePromoStateChange = (e) => {
    setPromoState({ ...promoState, [e.target.name]: e.target.value });
  };

  //wrapper function for handling the react-quill rich-text input specifically
  const handleDescriptionChange = (value) =>
    setPromoState({ ...promoState, description: value });

  useEffect(() => {
    //loads more events when viewport intersects with #bottom-boundary
    observer.observe(document.querySelector('#bottom-boundary'));
  }, []);

  return (
    // <PromoState>
    <Router>
      <MainStyle>
        <Switch>
          <Route exact path='/'>
            <Home allEvents={allEvents} />
          </Route>
          <Route exact path='/create'>
            <CreatePromo
              promoState={promoState}
              handlePromoStateChange={handlePromoStateChange}
              handleDescriptionChange={handleDescriptionChange}
              handleSetAllEvents={handleSetAllEvents}
            />
          </Route>
          <Route path='/search'>
            <SearchEvents />
          </Route>
          <Route path='/social'>
            <Social />
          </Route>
        </Switch>
      </MainStyle>
    </Router>
    // </PromoState>
  );
};

export default App;

2 个答案:

答案 0 :(得分:1)

您将在每次更新时创建一个新的观察者。这就是为什么将观察者添加到依赖数组会导致无限循环的原因。

尝试将创建IntersectionObserver和相关功能移至useEffect。 这样可以避免在每次更新时创建新的观察者。

此外,您可能想取消观察/销毁IntersectionObserver效果清除。

要说为什么您的回调两次被触发却看不到输出,这并不容易。如果您可以在codesandbox / jsfiddle中附加最低限度的复制,将会更容易。

...
useEffect(() => {
let options = {
    root: null,
    rootMargin: '0px',
    threshold: 1.0,
  };

  let eventsToShow = 0;

  // instantiate intersection observer.
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      console.log(entry);
      console.log(entry.isIntersecting);
    });
    eventsToShow += 4;
    console.log('trigger');
    getEvents(eventsToShow);
  }, options);

  //defines our backend api call to get events
  const getEvents = async (numberOfEvents) => {
    try {
      const events = await fetch(
        `http://localhost:3001/api/events/${numberOfEvents}`
      );
      const newData = await events.json();
      setAllEvents(allEvents => [...allEvents, ...newData]);
      return newData;
    } catch (error) {
      console.log(error);
    }
  };
    //loads more events when viewport intersects with #bottom-boundary
    observer.observe(document.querySelector('#bottom-boundary'));

    // destroy observer
    return observer.disconnect;
  }, []);
...

答案 1 :(得分:1)

我知道了。

当底部边界元素进入和退出视口时,触发了我的回调。可以通过forEach循环中的条件轻松检查条件,即检查entry.isIntersecting的值,并且仅在isIntersecting === true时才触发回调。