reactjs 为什么我的scrollWidth显示错误的数字?

yquaqz18  于 2022-11-22  发布在  React
关注(0)|答案(3)|浏览(194)

我正在尝试做的事情我正在使用React JS构建一个Netflix克隆。我已经创建了一个视频组件列表来水平列出视频项。我已经将容器的overflow-x设置为隐藏,这样我就可以使用左按钮和右按钮来左右滚动。通过isOverflowLeft和isOverflowRight的布尔值,我想让按钮显示:当没有溢出时为none。我使用useRef()使这个函数工作。当单击左键或右键时,scrollLeft更新为+- 400。
问题问题是当组件呈现时,scrollWidth显示了一个不同的数字。在我的例子中,scrollWidth应该是4000,但它显示的宽度与clientWidth相同。你能检查我的代码并告诉我我哪里做错了吗?

const VideoList = memo(({ label, fetchUrl, isLarge }) => {
  const listRef = useRef();
  const [isOverflowLeft, setIsOverflowLeft] = useState(false);
  const [isOverflowRight, setIsOverflowRight] = useState(false);
  const [scrollLeft, setScrollLeft] = useState(0);

  const handleScrollRight = () => {
    if (isOverflowRight) {
      listRef.current.scrollLeft += 400;
      setScrollLeft((prev) => prev + 400);
    }
  };
  const handleScrollLeft = () => {
    if (isOverflowLeft) {
      listRef.current.scrollLeft -= 400;
      setScrollLeft((prev) => prev - 400);
    }
  };

  useEffect(() => {
    async function fetchData() {
      const requestOptions = {
        method: 'GET',
        redirect: 'follow',
      };
      await fetch(fetchUrl, requestOptions)
        .then((response) => response.json())
        .then((data) => setMovies(data.results))
        .catch((error) => console.log('error', error));
    }
    fetchData();
  }, [fetchUrl]);

  useEffect(() => {
    setIsOverflowLeft(scrollLeft > 0);
    setIsOverflowRight(
      scrollLeft + listRef.current.clientWidth < listRef.current.scrollWidth
    );
    console.log(
      `clientWidth: ${listRef.current.clientWidth} scrollWidth: ${listRef.current.scrollWidth} scrollLeft: ${scrollLeft} isOverflowLeft: ${isOverflowLeft} isOverflowRight: ${isOverflowRight}`
    );
  }, [scrollLeft, isOverflowLeft, isOverflowRight]);

  return (
    <section className={styles.container}>
      <h1 className={styles.title}>{label}</h1>
      <div className={styles.list} ref={listRef}>
        <button
          className={isOverflowLeft ? styles.scrollLeft : styles.hidden}
          onClick={handleScrollLeft}
        >
          <BsChevronCompactLeft className={styles.scrollIcon} />
        </button>
        {movies.map((movie) => {
          return <VideoItem key={movie.id} video={movie} isLarge={isLarge} />;
        })}
        <button
          className={isOverflowRight ? styles.scrollRight : styles.hidden}
          onClick={handleScrollRight}
        >
          <BsChevronCompactRight className={styles.scrollIcon} />
        </button>
      </div>
    </section>
  );
});

export default memo(VideoList);

屏幕截图x1c 0d1x

b4lqfgs4

b4lqfgs41#

尝试将listRef.current添加到useEffect依赖项数组中,因为当列表元素溢出时,listRef.current值会发生变化,然后它会给予您正确的.scrollWidth值。因此,您的代码应该如下所示:

... 
useEffect(() => {
    setIsOverflowLeft(scrollLeft > 0);
    setIsOverflowRight(
      scrollLeft + listRef.current.clientWidth < listRef.current.scrollWidth
    );
    console.log(
      `clientWidth: ${listRef.current.clientWidth} scrollWidth: ${listRef.current.scrollWidth} scrollLeft: ${scrollLeft} isOverflowLeft: ${isOverflowLeft} isOverflowRight: ${isOverflowRight}`
    );
  }, [listRef.current, scrollLeft, isOverflowLeft, isOverflowRight]);
...
92vpleto

92vpleto2#

我遇到了同样的问题,我找到了一个解决办法,我想通过计算滚动和更新滑块的宽度来设置滑块的约束。显然,问题是在页面呈现后。scrollWidth和.offsetWidth/.clientWidth返回相同的值。所以我在执行useEffect中的内容之前添加了一个小延迟,它起作用了。下面是我的代码:

const [width, setWidth] = useState(0);
  const carousel = useRef();

  useEffect(() => {
    setTimeout(() => {
      setWidth(carousel.current.scrollWidth - carousel.current.offsetWidth);
    }, 2000);
  }, [carousel]);
goucqfw6

goucqfw63#

这里也有同样的问题,但是我了解到可以使用requestAnimationFrameuseEffect中获得正确和准确的scrollWidth

useEfect(() => {
    ...

    requestAnimationFrame(() => {
        // get DOM node's height, width, top, left, right and bottom here.
        exampleElementRef.current.getBoundingClientRect();
    })

    ...
}, [])

相关问题