交集观察服务器 api / useEffect 钩子触发回调两次的问题



我不确定为什么,但我所做的一些事情导致我的 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;

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

尝试将创建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;
}, []);
...

我想通了。

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

最新更新