首页 > 解决方案 > useEffect 中的 IntersectionObserver 只工作一次

问题描述

我正在使用反应和交叉点观察者 api 构建一个无限滚动应用程序。

但我被困在intersectionObserver 只有一次在useEffect 中的部分。

这是代码

import React, { useState, useEffect, createRef } from 'react';
import axios from 'axios';

function App() {
  const [page, setPage] = useState(1);
  const [passengers, setPassengers] = useState([]);
  const bottomRef = createRef();

  const scrollCallback = (entries) => {
    if (entries[0].isIntersecting) {
      axios.get(`https://api.instantwebtools.net/v1/passenger?page=${page}&size=10`).then(res => setPassengers(prevState => [...prevState, ...res.data.data]));
    }
  }; 
  
  useEffect(() => {
    const observer = new IntersectionObserver(scrollCallback, {
      root: null,
      threshold: 1,
    });
    observer.observe(bottomRef.current);
    return () => {
      observer.disconnect();
    }
  }, [bottomRef]);

  return (
    <div className="container">
      <div className="lists">
        {
          passengers.map((passenger, idx) => {
            const { airline, name, trips } = passenger;
              return (
                 <div className="list" key={idx}>
                   <h4>User Info</h4>
                   <p>name: {name}</p>
                   <p>trips: {trips}</p>
                   <h4>Airline Info</h4>
                   <p>name: {airline.name}</p>
                   <p>country: {airline.country}</p>
                   <p>established: {airline.established}</p>
                   <p>head quarter: {airline.head_quarters}</p>
                   <p>website: {airline.website}</p>
                 </div>
              )
            })
        }
      </div>
      <div ref={bottomRef} />
    </div>
  );
}

当滚动到达底部时,scrollCallbackuseEffect 中的函数可以将两个数组合并为一个,并最终显示我想要查看的合并数据。

然而,这只工作一次。useEffect 生命周期不再起作用。所以我改为observer.disconnect();但是observer.unobserve(bottomRef.current);这发生了一个错误说

TypeError: Failed to execute 'unobserve' on 'IntersectionObserver': parameter 1 is not of type 'Element'.

为什么useEffect生命周期无法读取bottomRef

工作代码示例:https ://codesandbox.io/s/dazzling-newton-jvivj?file=/src/App.js

奇怪的是codeandbox中的代码有效

标签: javascriptreactjsintersection-observer

解决方案


如果你可以observe参考,你当然unobserve也可以,只要你有正确的、相同的参考。

useEffect(() => {
  const observer = new IntersectionObserver(scrollCallback, {
    root: null,
    threshold: 1,
  });
  const {current} = bottomRef;
  observer.observe(current);
  return () => {
    observer.unobserve(current);
  };
}, [passengers]);

这永远不会说current不是节点。

此外,如果发生了变化passengers,您最好保留该引用,而不是保留永远不会改变的东西,因为bottomRef它是current包装器,但它不会“永远”改变,而passengers状态一旦相交就会改变。

交替地

由于bottomRef不打算改变,您也可以只观察该节点而从不清理它的观察。

useEffect(() => {
  const observer = new IntersectionObserver(scrollCallback, {
    root: null,
    threshold: 1,
  });
  observer.observe(bottomRef.current);
}, [bottomRef]);

无论哪种方式都应该解决问题。


推荐阅读