You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何封装实现同步滚动的React ScrollDivs可复用组件?

How to Build a Reusable Synchronized Scroll Component in React

Great question! Let's turn your existing synchronized scroll logic into a clean, reusable ScrollDivs component that hides all the implementation details from the user. Here's a modern, function-component-based solution using React hooks:

The Reusable ScrollDivs Component

import React, { useRef } from 'react';

const ScrollDivs = ({ children }) => {
  // Store references to all child div elements
  const divRefs = useRef([]);

  // Handle scroll sync logic
  const handleScroll = (e) => {
    const { scrollLeft, scrollTop } = e.target;
    // Sync scroll position across all divs, skip the scrolled div itself to avoid redundant updates
    divRefs.current.forEach(ref => {
      if (ref && ref !== e.target) {
        ref.scrollLeft = scrollLeft;
        ref.scrollTop = scrollTop;
      }
    });
  };

  // Process each child to add ref and scroll handler
  const processedChildren = React.Children.map(children, (child, index) => {
    // Only modify div elements (adjust this check if you need to support other scrollable elements)
    if (child.type === 'div') {
      // Merge user's existing onScroll with our sync handler if present
      const combinedOnScroll = child.props.onScroll 
        ? (e) => { child.props.onScroll(e); handleScroll(e); } 
        : handleScroll;

      return React.cloneElement(child, {
        ref: (el) => (divRefs.current[index] = el),
        onScroll: combinedOnScroll
      });
    }
    // Return non-div children unchanged
    return child;
  });

  return <div>{processedChildren}</div>;
};

export default ScrollDivs;

Key Details Explained

  • divRefs: Uses useRef to maintain an array of DOM references to all the child divs we want to sync. This persists across component re-renders without triggering unnecessary state updates.
  • handleScroll: When any div is scrolled, it captures the current scroll position and applies that position to all other divs in the ref array. We skip the target div itself to avoid redundant DOM operations.
  • Child Processing: Uses React.Children.map and React.cloneElement to safely modify each child div:
    • Adds a ref to store the DOM element in our divRefs array
    • Attaches the sync scroll handler, and merges any existing onScroll prop from the user so their custom logic still runs alongside the sync functionality

How to Use the Component

Users can now wrap any number of scrollable divs inside <ScrollDivs> without worrying about the underlying sync logic:

import ScrollDivs from './ScrollDivs';

// Example usage
const App = () => {
  return (
    <div style={{ border: '1px solid tomato', padding: '8px' }}>
      <ScrollDivs>
        <div style={{ width: 300, height: 100, overflow: 'auto', border: '1px solid black', margin: '2px 0' }}>
          <div style={{ width: 500, height: 400 }}>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Scelerisque eu ultrices vitae auctor eu augue ut lectus. In fermentum et sollicitudin ac orci.
          </div>
        </div>
        <div style={{ width: 300, height: 100, overflow: 'auto', border: '1px solid black', margin: '2px 0' }}>
          <div style={{ width: 500, height: 400 }}>
            Velit sed ullamcorper morbi tincidunt ornare. Auctor eu augue ut lectus arcu bibendum. Non nisi est sit amet. Facilisis magna etiam tempor orci eu lobortis. Et tortor at risus viverra adipiscing at in tellus integer.
          </div>
        </div>
        <div style={{ width: 300, height: 100, overflow: 'auto', border: '1px solid black', margin: '2px 0' }}>
          <div style={{ width: 500, height: 400 }}>
            Lacus luctus accumsan tortor posuere ac ut consequat semper viverra. Fermentum dui faucibus in ornare quam viverra orci sagittis. Porttitor eget dolor morbi non. Pulvinar pellentesque habitant morbi tristique senectus et.
          </div>
        </div>
      </ScrollDivs>
    </div>
  );
};

export default App;

Bonus: Class Component Version (For Legacy Codebases)

If you need a class-based implementation for older React projects, here's how you'd structure it:

import React from 'react';

class ScrollDivs extends React.Component {
  constructor(props) {
    super(props);
    this.divRefs = [];
  }

  handleScroll = (e) => {
    const { scrollLeft, scrollTop } = e.target;
    this.divRefs.forEach(ref => {
      if (ref && ref !== e.target) {
        ref.scrollLeft = scrollLeft;
        ref.scrollTop = scrollTop;
      }
    });
  };

  render() {
    const processedChildren = React.Children.map(this.props.children, (child, index) => {
      if (child.type === 'div') {
        const combinedOnScroll = child.props.onScroll 
          ? (e) => { child.props.onScroll(e); this.handleScroll(e); } 
          : this.handleScroll;

        return React.cloneElement(child, {
          ref: (el) => (this.divRefs[index] = el),
          onScroll: combinedOnScroll
        });
      }
      return child;
    });

    return <div>{processedChildren}</div>;
  }
}

export default ScrollDivs;

This component is flexible, user-friendly, and abstracts all the sync complexity away—exactly what you're looking for!

内容的提问来源于stack exchange,提问作者user6456564

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:54:07