【问题标题】:Problem with intersection oberserver api / useEffect hook triggering callback twice交叉点观察者 api / useEffect 钩子触发回调两次的问题
【发布时间】:2020-05-24 01:41:29
【问题描述】:

我不完全确定为什么,但我所做的事情是导致我的intersectionObserver 实例中的回调触发2 次,而它应该只触发1 次。 任何关于为什么会这样的见解将不胜感激。

在这个组件中发生的其他事情中,我试图设置 insersectionObserver 来观察我称为底部边界的元素,方法是在 useEffect() 挂钩内调用我的观察者实例上的观察方法。这工作正常,除了观察者触发我的回调两次。我尝试将观察者添加到依赖数组中,并尝试将 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;

【问题讨论】:

    标签: reactjs use-effect intersection-observer


    【解决方案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;
      }, []);
    ...
    

    【讨论】:

    • 不幸的是,将这些语句重新定位到 useEffect 并没有改变任何东西。我会尽快一起获得一个最低限度的复制回购。
    【解决方案2】:

    我想通了。

    当底部边界元素进入和退出视口时,我的回调被触发。使用 forEach 循环中的条件检查 entry.isIntersecting 的值很容易解决,并且仅在 isIntersecting === true 时触发我的回调。

    【讨论】:

      猜你喜欢
      • 2021-09-23
      • 2021-07-20
      • 2018-10-18
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 2012-01-26
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多