【发布时间】:2021-08-28 17:35:30
【问题描述】:
我正在创建一个 useInfiniteScroll 只是为了练习制作自定义挂钩。
这就像
import { useEffect, useRef, useState } from "react";
const isHitBottom = () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
return scrollTop + clientHeight >= scrollHeight;
};
export function useInfiniteScroll() {
console.log("RENDERED");
const ref = useRef<NodeJS.Timeout | null>(null);
const [isAtBottom, setIsAtBottom] = useState<boolean>(false);
const debounced = () => {
if (ref.current) {
clearTimeout(ref.current);
}
ref.current = setTimeout(() => {
const isBottom = isHitBottom();
if (isBottom) {
console.log("HIT BOTTOM");
setIsAtBottom(true);
} else {
console.log("NOT HIT BOTTOM");
setIsAtBottom(false);
}
}, 500);
};
useEffect(() => {
window.addEventListener("scroll", debounced);
return () => {
window.removeEventListener("scroll", debounced);
};
}, []);
return isAtBottom;
}
另一个使用这个自定义钩子的组件的简化版本是
import React from "react";
import { useInfiniteScroll } from "../../hooks/useInfiniteScroll";
const Content: React.FC<ContentProps> = (props) => {
useInfiniteScroll();
return <div>test</div>;
};
export default Content;
每当isAtBottom 状态发生变化时,RENDERED 就会被记录,这很好。
但奇怪的部分是 RENDERED 如果我在不更改状态的情况下重播,则会再次被记录。
要重现,将滚动位置留在页面中间,
-
将滚动条移至底部 =>
HIT BOTTOM和RENDERED被记录。 -
向上滚动一点 =>
NOT HIT BOTTOM和RENDERED被记录。 -
向上滚动一点 =>
NOT HIT BOTTOM和RENDERED被记录。 (这是有问题的步骤,因为我预计它不会被渲染。) -
向上滚动一点 => 仅记录
NOT HIT BOTTOM。
同样的事情发生在相反的状态。
为什么会渲染两次?
【问题讨论】:
标签: javascript reactjs typescript react-hooks