0

コンポーネントをマウスでスライド可能にしようとしています。しかし、マウスを離すと、実行中にDOM要素の1つの参照がnullになり、その理由がわかりません。

問題を説明するためにサンドボックスを作成しました。(これは完全な実装ではありません。問題を実験するために必要なものだけです)。

要素をドラッグしてコンソールを確認するだけです。ref が最初は正しく設定されていることがわかりますが、マウスを放すと、ref が消えます。

これがいつ、なぜ起こっているのかわかりません。

完全な App.js ファイルは次のとおりです。

import React from "react";
import styled from "styled-components";

const Container = styled.div`
  width: 100%;
  overflow: hidden;
`;

const Slides = styled.div`
  position: relative;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
`;

const Slide = styled.div`
  width: ${props => props.size}%;
  cursor: pointer;
  height: 100%;
  display: inline-block;
`;

const Carrousel = ({
  children,
  columnCount = 1,
  onSlideChanged = () => {},
  active = 0
}) => {
  const [dragging, setDragging] = React.useState(false);
  const initialMouseX = React.useRef(0); // Starting drag x coordinates
  const initialLeft = React.useRef(0); // Left value when the drag started
  const currentLeft = React.useRef(-active * (100 / children.length)); // Current left value
  const sliderRef = React.createRef();
  const slidesRef = React.createRef();

  // This will directly manipulate the DOM for better performances
  const setLeft = React.useCallback(
    newLeft => {
      currentLeft.current = newLeft;
      if (!slidesRef.current) return;
      slidesRef.current.style.left = currentLeft.current + "%";
    },
    [currentLeft, slidesRef]
  );

  // Starts the drag
  const startDrag = ({ screenX }) => {
    setDragging(true);
    initialMouseX.current = screenX;
    initialLeft.current = currentLeft.current;
  };
  // We need the references to be updated before being able to listen to move and mouseup events
  React.useLayoutEffect(() => {
    if (!dragging) return;
    console.log("at last render, slidesRef was:", slidesRef.current);
    const move = event => {
      if (dragging && sliderRef.current) {
        const width = sliderRef.current.getBoundingClientRect().width;
        const newLeft =
          initialLeft.current +
          ((event.screenX - initialMouseX.current) * 100) / width;
        setLeft(newLeft);
        event.preventDefault();
      }
    };
    const stopDrag = () => {
      setDragging(false);
      console.log("when calling stopDrag, slidesRef was:", slidesRef.current);
    };
    document.addEventListener("mouseup", stopDrag);
    document.addEventListener("mousemove", move);
    return () => {
      document.removeEventListener("mousemove", move);
      document.removeEventListener("mouseup", stopDrag);
    };
  }, [initialLeft, dragging, sliderRef, setLeft, slidesRef]);

  return (
    <Container ref={sliderRef}>
      <Slides ref={slidesRef} onMouseDown={startDrag}>
        {children.map((child, index) => (
          <Slide key={index} size={100 / columnCount}>
            {child}
          </Slide>
        ))}
      </Slides>
    </Container>
  );
};

const App = () => (
  <Carrousel columnCount={2}>
    {new Array(4).fill("").map((_, i) => (
      <div key={i}>
        <span>Test{i + 1}</span>
      </div>
    ))}
  </Carrousel>
);

export default App;

問題はこの部分にあります:

  React.useLayoutEffect(() => {
    if (!dragging) return;
    console.log("at last render, slidesRef was:", slidesRef.current);
    const move = event => {
      if (dragging && sliderRef.current) {
        const width = sliderRef.current.getBoundingClientRect().width;
        const newLeft =
          initialLeft.current +
          ((event.screenX - initialMouseX.current) * 100) / width;
        setLeft(newLeft);
        event.preventDefault();
      }
    };
    const stopDrag = () => {
      setDragging(false);
      console.log("when calling stopDrag, slidesRef was:", slidesRef.current);
    };
    document.addEventListener("mouseup", stopDrag);
    document.addEventListener("mousemove", move);
    return () => {
      document.removeEventListener("mousemove", move);
      document.removeEventListener("mouseup", stopDrag);
    };
  }, [initialLeft, dragging, sliderRef, setLeft, slidesRef]);

ドラッグすると: を取得at last render, slidesRef was: <div ...> し、リリースすると:when calling stopDrag, slidesRef was: null

4

0 に答える 0