admin管理员组

文章数量:1296257

I am attempting to track the scroll progress when this element scrolls horizontally. Everything works well – except when I use the useCenterColumn hook to adjust the size of the children within the parent element whose scroll I am tracking.

The scroll event on the parent element stops firing completely (both the ref?.addEventListener and the div's onScroll stop). I've tried using useLayoutEffect and useInsertionEffect here but those don't seem to change anything.

What do I have to do to ensure this sliderRef continues to fire scroll events after useCenterColumn changes the layout?

This is a NextJS v15 app, so I'm also wondering if this is producing side effects.

import { FC, useEffect, useRef, useState } from "react";
import cx from "classnames";
import Link from "next/link";

import { BlockWrapper, Image } from "components";
import { useSliderMutate } from "contexts/SliderContext";

const Breakpoints: { [key: string]: number } = {
  xs: 0,
  xl: 1200,
  "3xl": 1920,
};

const ContainerPadding: { [key: string]: number } = {
  xs: 29,
  xl: 60,
  "3xl": 96,
};

const useCenterColumn = () => {
  const [centerColumn, setCenterColumn] = useState(0);

  useEffect(() => {
    const updateCenterColumn = () => {
      const vw =
        typeof window !== "undefined" ? Math.max(window?.innerWidth || 0) : 0;
      const breakpoints = Object.keys(Breakpoints);
  
      const breakpoint = breakpoints.find((key, i) => {
        if (i === breakpoints.length - 1) return vw >= Breakpoints[key];
        return vw >= Breakpoints[key] && vw < Breakpoints[breakpoints[i + 1]];
      });
  
      if (!breakpoint) return 0;
  
      const padding = ContainerPadding[breakpoint];
  
      const result = breakpoint === "3xl"
        ? Math.min(((vw - padding * 2) / 14) * 12 - 20, ((1920 - padding * 2) / 14) * 12 - 20)
        : ((vw - padding * 2) / 14) * 12 - 20;
      
      setCenterColumn(result);
    };
    window.addEventListener("resize", updateCenterColumn);
    updateCenterColumn();
    return () => window.removeEventListener("resize", updateCenterColumn);
  }, []);

  return centerColumn;
};

const ImageSlider: FC<any> = ({ items, meta }) => {
  const sliderRef = useRef<HTMLDivElement | null>(null);
  const mutate = useSliderMutate();
  const centerColumn = useCenterColumn();

  useEffect(() => {
    const ref = sliderRef.current;

    const handleScroll = () => {
      const max = (ref?.scrollWidth || 0) - (ref?.offsetWidth || 0);
      const current = ref?.scrollLeft || 0;
      const position = (current / max) * 100 || 0;

      mutate?.setScrollPosition(meta.key, position);
    };

    handleScroll();
    window.addEventListener("resize", handleScroll, true);
    ref?.addEventListener("scroll", handleScroll, true);

    return () => {
      window.removeEventListener("resize", handleScroll);
      ref?.removeEventListener("scroll", handleScroll);
    };
  }, [sliderRef, mutate, meta.key, centerColumn]);

  return (
    <BlockWrapper layout="full" className="ImageSlider">
      <div className="ImageSlider__container w-full max-w-full mx-auto overflow-auto _scroll-hide relative">
        <div
          key={`Slider-Track--${meta.key}`}
          ref={sliderRef}
          onScroll={() => console.log('SCROLLL')}
          className="ImageSlider__track w-fit flex pl-7 md:pl-[calc((100vw-(28px*2))/14+28px)] lg:pl-[calc((100vw-(38px*2))/14+38px)] xl:pl-[calc((100vw-(60px*2))/14+60px)] 2xl:pl-[calc((100vw-(76px*2))/14+76px)] 3xl:pl-[calc(max(((100vw-(96px*2))/14)+96px,(100vw-(1728px/14*12))/2))] relative overflow-auto _scroll-hide"
        >
          {items.map((item) => {
            return (
              <Link
                key={item._key}
                href={item.url || ""}
                className={cx(
                  "relative flex-shrink-0 block mr-5 lg:mr-[26px] xl:mr-8 2xl:mr-10 3xl:mr-[52px] md:last:mr-[calc((100vw-(28px*2))/14+28px)] lg:last:mr-[calc((100vw-(38px*2))/14+38px)] xl:last:mr-[calc((100vw-(60px*2))/14+60px)] 2xl:last:mr-[calc((100vw-(76px*2))/14+76px)] 3xl:last:mr-[calc(max(((100vw-(96px*2))/14)+96px,(100vw-(1728px/14*12))/2))]",
                  {},
                )}
                style={{
                  width: (centerColumn / 6) * 5 - 20,
                }}
              >
                <Image src="" alt="" />
              </Link>
            );
          })}
        </div>
      </div>
    </BlockWrapper>
  );
};

export default ImageSlider;

If I remove the use of useCenterColumn everything works as expected although the item elements are sized incorrectly.

本文标签: reactjsuseRef scroll event stops firing on parent after useEffect resizes ref39s childrenStack Overflow