在多个元素上React Intersection Observer



我有一个代码使用下面的react-intersection-observer:
https://codesandbox.io/s/multiple-observe-elements-ieoh8u?file=/src/App.js

我试图找出哪一个是当前的图像在视图中,当你向下滚动到页面中间,Image 1Image 2都在视图中,下面的指示器在图像1和2之间不断闪烁。

我想要链接它不会切换到图像2,直到图像1完全从视图中消失。

如何实现这一点?

在你的代码中有几件事会导致问题。

  1. Page需要移出App组件。现在它会在App组件的每次渲染中被重新定义。

  2. 你需要使用useEffect(或类似的)钩子来跟踪状态变化。否则这些回调将在每次渲染时调用。

  3. 需要有一种方法来跟踪当前哪些图像是可见的,哪些是不可见的。

我注释了下面的更改以使代码工作:

import * as React from "react";
import { useInView } from "react-intersection-observer";
import "./styles.css";
//Change no. 1: moved Page component outside App component
function Page({ data, onPageChange }) {
const { ref, inView, entry } = useInView({
threshold: 0
});
//Change no 2: moved in an useEffect and added inView as second parameter
React.useEffect(() => {
onPageChange(data.name, inView);
}, [inView, onPageChange, data.name]);
return (
<div>
{data.name} below
<img ref={ref} src={data.image} alt={data.name} />
</div>
);
}
export default function App() {
//Change no 3: wrapped data to useMemo
const data = React.useMemo(() => [
{
name: "Image 1",
image:
"https://cms-assets.tutsplus.com/cdn-cgi/image/width=850/uploads/users/107/posts/26488/final_image/41-space-scrolling-background850-2.jpg"
},
{
name: "Image 2",
image:
"https://cms-assets.tutsplus.com/cdn-cgi/image/width=850/uploads/users/107/posts/26488/final_image/41-space-scrolling-background850-2.jpg"
}
], []);
const [inViewName, setInViewName] = React.useState(1);
//Change no 4: Added help object to track visible images
const [allVisible, setAllVisible] = React.useState({});
//Change no 5: updating the allVisible object here with correct state
const onPageChange = React.useCallback((name, inView) => {
setAllVisible((old) => ({ ...old, [name]: inView }));
}, []);
//Change no 6: Finding first visible image and updating inViewName accordingly
React.useEffect(() => {
let firstVisible = data.find((img) => allVisible[img.name]);
if (firstVisible) {
setInViewName(firstVisible.name);
}
}, [allVisible, data]);
return (
<div className="App">
{data.map((page, i) => (
<Page key={i} data={page} onPageChange={onPageChange} />
))}
<div className="NameIndicator">{inViewName}</div>
</div>
);
}

请注意,可能有更简单的方法来创建此功能。例如,可以使用refs并将所有逻辑放在应用程序级别。

最新更新