简体   繁体   中英

How do I test event.target against a React element?

I'm new to React and want to learn by practicing. I'm trying to implement a draggable component, which wraps a child element and captures mouse events, then fires a function passed down from props which in turn updates the state (and the relevant CSS).

My draggable component looks like this:

import React from "react";
import PropTypes from "prop-types";

export default class Draggable extends React.Component {
  constructor(props) {
    super(props);
    this.mouseMove = this.mouseMove.bind(this);
    this.mouseUp = this.mouseUp.bind(this);
    this.beginDrag = this.beginDrag.bind(this);
    this.state = {
      isDragging: false,
      lastX: 0,
      lastY: 0
    };
  }

  static propTypes = {
    onDrag: PropTypes.func.isRequired,
    children: PropTypes.element.isRequired
  };

  render() {
    const child = React.Children.only(this.props.children);
    const newChild = React.cloneElement(child, {
      onMouseDown: this.beginDrag
    });

    return newChild;
  }

  componentDidMount() {
    window.addEventListener("mousemove", this.mouseMove.bind(this));
    window.addEventListener("mouseup", this.mouseUp.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener("mousemove", this.mouseMove);
    window.removeEventListener("mouseup", this.mouseUp);
  }

  mouseMove(e) {
    if (this.state.isDragging) {
      const deltas = {
        x: e.clientX - this.state.lastX,
        y: e.clientY - this.state.lastY
      };

      this.setState({
        lastX: e.clientX,
        lastY: e.clientY
      });

      this.props.onDrag(deltas);
    }
  };

  mouseUp() {
    if (this.state.isDragging) {
      this.setState({
        isDragging: false
      });
    }
  };

  beginDrag(e) {
    this.setState({
      isDragging: true,
      lastX: e.clientX,
      lastY: e.clientY
    });
  };
}

With example usage:

import React from "react";
import Draggable from "./Draggable";

export default class SomeComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      translateX: 0,
      translateY: 0
    };
  }

  render() {
    const style = {
      top: this.state.translateY,
      left: this.state.translateX
    };

    return (
      <Draggable onDrag={this.onDrag}>
        <div className="someComponent">
          <div className="dragContainer" style={style}>
            <div className="block">
              hello world
            </div>
            <div className="block">
              hello world
            </div>
            <div className="block">
              hello world
            </div>
          </div>
        </div>
      </Draggable>
    );
  }

  onDrag = (deltas) => {
    this.setState(state => ({
      translateX: state.translateX + deltas.x,
      translateY: state.translateY + deltas.y
    }));
  };
}

The relevant SCSS:

.someComponent {
  display: block;
  width: 100%;
  height: 100%;
  position: relative;

  .dragContainer {
    position: absolute;
  }

  .block {
    display: inline-block:
  }
}

The problem

Dragging does work, in the sense that when I drag the container around, the contents of .dragContainer are translated as expected.

The thing is, dragging also works when I begin dragging from any child element (say, one of the .block s). I could mitigate that by testing for e.target in Draggable.beginDrag , but I have no idea what to test it against. Ideally I would compare e.target against the child element passed in props but since it's virtual DOM I'm pretty sure it won't work.

What should I compare e.target with? I've read about React.createRef but I'm not sure how to use it in this scenario.

e.target should give access to the DOM node being clicked. Why not compare event.target.id to an id you give each of your blocks? Then you can do what you want based on the result of that comparison.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM