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

React自定义轮播onMouseMove结合useState触发大量重渲染卡顿如何解决

React自定义轮播拖拽卡顿优化方案

问题根源

当前卡顿的核心原因是:onMouseMove触发时每次调用setPosition都会触发整个Carousel组件的全量重渲染,鼠标滑动过程中1秒会触发几十次重渲染,自然会出现掉帧卡顿。你用普通let变量无法生效是因为函数组件每次渲染都会重置作用域内的普通变量,且变量变更不会驱动视图更新。

最优解决方案

用useRef存储中间状态+直接操作DOM样式,完全绕过React的状态更新渲染流程,不会触发任何不必要的重渲染,性能最优。
改造后的完整代码如下:

import { ReactNode, useRef } from "react";

interface CarouselProps {
  children: ReactNode;
}

const Carousel = ({
  children,
}: CarouselProps): JSX.Element => {
  // 存储要移动的DOM节点,直接操作样式
  const slideRef = useRef<HTMLDivElement>(null);
  // 用ref存所有中间状态,修改current不会触发重渲染
  const isMouseLocked = useRef(false);
  const initialPosition = useRef(0);
  const lastPosition = useRef(0);
  const currentPosition = useRef(0);

  function handleMouseDown(event: React.MouseEvent): void {
    event.preventDefault();
    isMouseLocked.current = true;
    initialPosition.current = event.clientX;
    // 把事件绑定到window,避免鼠标移出组件后失效
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
  }

  function handleMouseMove(event: MouseEvent): void {
    if (!isMouseLocked.current) return;
    const travelDistance = event.clientX - initialPosition.current;
    currentPosition.current = travelDistance + lastPosition.current;
    // 直接操作DOM修改transform,不走React状态更新
    slideRef.current?.style.setProperty('transform', `translateX(${currentPosition.current * 2}px)`);
  }

  function handleMouseUp(event: MouseEvent): void {
    event.preventDefault();
    lastPosition.current = currentPosition.current;
    isMouseLocked.current = false;
    // 清理window上的事件监听,避免内存泄漏
    window.removeEventListener('mousemove', handleMouseMove);
    window.removeEventListener('mouseup', handleMouseUp);
  }

  return (
    <div
      className="carousel"
      onMouseDown={handleMouseDown}
    >
      <div
        ref={slideRef}
      >
        {children}
      </div>
    </div>
  );
};

export default Carousel;

额外优化建议

  • 可以给位移更新加requestAnimationFrame包裹,保证样式更新和浏览器重绘节奏对齐,进一步减少掉帧
  • 如果拖拽结束后需要把最终位移同步到state做其他逻辑(比如自动对齐轮播项、切换页码),只需要在handleMouseUp里更新一次state即可,不会产生性能问题
  • 你原代码中setInicialPosition存在拼写错误,正确拼写应为setInitialPosition,如果后续需要用到state可以注意修正

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 12:06:02