🙆

# ReactでScrollingの方法

2024/09/04に公開

ReactでScrollingの方法

1. 簡単な方法

DOMElementRef.current.scrollIntoView()

const componentRef = useRef(null);

useEffect(() => {
  if(componentRef != null && componentRef.current != null && 他の条件){
    // componentRefを見えるようにscrollingを実行する
    componentRef.current.scrollIntoView({
        block: 'nearest',
        inline: 'nearest',
        behavior: 'smooth'
    });
  }
}

// componentRefをDOM Elementに付ける
return (
  <div ref={componentRef} ... >
    <YourComponent />
  </div>
)
  • 欠点
    • Scrollingの位置がうまくコントロールできない
    • 無効になるケースもある
    • どのContainerに対してScrollするかコントロールできない
      • window / the nearest container

2. Customizeの方法

container.current.scrollTo(left, top, behavior)

  • containerはCSSでoverflow-x-auto overflow-y-auto などを設定されるScrollable領域

    const ref = useRef(null);
    
    return (
      <div ref={ref} className={"overflow-x-auto h-full scrollbar"}>
        <YourComponent2 parentRef={ref}/>
      </div>
    )
    
  • YourComponent2 の中にcontainerのrefを渡して、componentの現在の位置とcontainerの位置を比べて、
    Containerのscrollingの位置を計算する

    function YourComponent2({ parentRef, ... }) {
      // scrollRefがComponentのDOM elementのRef
    
      useEffect(() => {
      if (scrollRef && scrollRef.current) {
        // scroll the board by horizontal scrolling
        const eleBoundingRect = scrollRef.current.getBoundingClientRect();
        if (parentRef && parentRef.current) {
          const parentBoundingRect = parentRef.current.getBoundingClientRect();
          const extraXRight =
            eleBoundingRect.x +
            eleBoundingRect.width -
            (parentBoundingRect.x + parentRef.current.clientWidth);
          const extraXLeft = parentBoundingRect.x - eleBoundingRect.x;
    
          if (extraXRight >= 0) {
            // scroll the container to the right
            parentRef.current.scrollTo({
              left: parentRef.current.scrollLeft + extraXRight,
              behavior: "smooth",
            });
          } else if (extraXLeft >= 0) {
            // scroll the container to the left
            parentRef.current.scrollTo({
              // parentRef.current.scrollLeft: current horizontal scroll of container
              left: Math.max(parentRef.current.scrollLeft - extraXLeft, 0),
              behavior: "smooth",
            });
          }
        }
      }
    }
    
  • Containerのscrollingの位置を計算する方法

    • Containerとcomponentがの現在viewportに対する位置情報を取得するref.current.getBoundingClientRect()

      https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

    • Containerが画面で見える部分のサイズを取得する parentRef.current.clientWidth

      https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth

    • Containerとcomponentの差分を計算して、Scrollingするかどうかを決める

      const extraXRight =
            eleBoundingRect.x +
            eleBoundingRect.width -
            (parentBoundingRect.x + parentRef.current.clientWidth);
      
    • Containerの現在のScrollingの位置情報を取得してparentRef.current.scrollLeft、差分を現在の位置に加える

      parentRef.current.scrollTo({
        left: parentRef.current.scrollLeft + extraXRight,
        behavior: "smooth",
      });
      

Discussion