0

我做了一个自定义钩子作为我的交叉点观察者,但我同时两次获得虚假和真实状态!,第一次是错误的(两次),第二次是正确的(两次)为什么会发生这种情况?为什么状态会改变自己?state 必须为真,因为 h3 是 100% 可见的。

这是代码:

应用程序.js

import React from "react";
import "./App.css";
import useIntersectionObserver from "./hooks/useIntersectionObserver";
function App() {
  const headingRef = React.useRef(null);
  const { observer, state } = useIntersectionObserver({ rootMargin: "10px" });
  React.useEffect(() => {
    if (headingRef.current instanceof Element) {
      observer.observe(headingRef.current);
    }
  }, []);
  console.log(state);
  return (
    <>
      <h3 ref={headingRef}>test page</h3>
      <h2>test page</h2>
    </>
  );
}

export default App;

使用IntersectionObserver 自定义钩子:

import React from "react";

const useIntersectionObserver = (options) => {
  const [state, setState] = React.useState(false);
  const callback = (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        setState(true);
      } else {
        setState(false);
      }
    });
  };
  const observer = new IntersectionObserver(callback, options);
  return { observer, state };
};

export default useIntersectionObserver;

这是奇怪的输出:(在初始渲染时) 在此处输入图像描述

4

1 回答 1

0

您的组件将在 Intersection Observer 观察到元素之前渲染,因此预计在第一次渲染(或前几次渲染)时状态将为 false。这不是一个真正的问题,但您可以进行一些改进以获得更一致的行为。

第一种是将观察者对象存储在 ref 中,以便只创建一个:

function useIntersectionObserver(options) {
  const [state, setState] = React.useState(false);
  
  // store the observer in a ref so only one is created
  const observer = React.useRef(new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        console.log("is visible")
        setState(true);
      } else {
        console.log("not visible")
        setState(false);
      }
    });
  }, options))
  
  return { observer: observer.current, state };
}

第二个是将观察者添加到你的 useEffect 的依赖数组并返回一个清理函数。这将确保您注册观察者的 useEffect 仅在观察者更改并且已正确清理时运行。

function App() {
  const headingRef = React.useRef(null);
  const { observer, state } = useIntersectionObserver({ rootMargin: "10px" });

  React.useEffect(() => {
    if (observer && headingRef.current) {
      observer.observe(headingRef.current);
    }
    
    // return cleanup function
    return () => {
      if (observer) {
        observer.disconnect();
      }
    }
  // correctly specify the observer as a dependency to this side effect
  }, [observer]);

  return (
    <>
      <h3 ref={headingRef}>test page</h3>
      <h2>test page</h2>
    </>
  );
}

完整的代码笔在这里: https ://codepen.io/spencercwood/pen/mdqegBZ ?editors=0011

在 codepen 上打开控制台,您会看到 IntersectionObserver 只打印一次“可见”。尝试调整渲染内容窗口的大小,使其不再可见,并且您将看到打印的“不可见”等。

于 2022-01-30T17:57:40.197 回答