Неправильная реакция onMouseEnter и onMouseLeave - PullRequest
0 голосов
/ 03 августа 2020

У меня есть div, который должен просто отображать «HOVERING», если курсор находится над ним, и «NOT HOVERING» в противном случае. По какой-то причине он ведет себя так, как ожидалось, если я медленно наведу на каждый div на странице; однако, если я быстро перемещаю курсор по экрану, некоторые из div переключаются. Это означает, что они будут отображать «NOT HOVERING», когда мой курсор перемещается по div, и «HOVERING», когда мой курсор не находится над div.

Эта ошибка возникает как в Chrome, так и в Safari.

Песочница:

https://codesandbox.io/s/aged-butterfly-r2g6x?file= / src / Geo. js

Быстро наведите курсор на поля, чтобы увидеть проблему.

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Проблема

Я думаю, что основная проблема с вашей реализацией заключается в том, как асинхронные обратные вызовы событий ставятся в очередь и обрабатываются в событии l oop. Я не могу найти каких-либо подробных сведений о задержке обработки обратных вызовов событий, но документы здесь и здесь могут пролить немного света на этот вопрос, если вы хотите углубиться.

В основном проблема двоякая:

  1. Одно событие l oop требует минутной продолжительности для обработки, т. Е. Обнаружения события и добавления его в очередь. Я подозреваю, что мышь движется достаточно быстро с экрана или с экрана или в другой div, который не обнаруживается. Дивы "прыжок" / "перемещение" при наведении также не очень помогают.
  2. Компонент logi c предполагает, что все события могут и будут обнаружены, и просто переключает предыдущее существующее состояние. Как только событие пропущено, переключение инвертируется, поэтому вы видите проблему. Даже в обновленной песочнице эта задержка может привести к зависанию одного из элементов.

Предлагаемое решение

Добавьте прослушиватель событий перемещения мыши к объекту окна и проверьте, Цель события перемещения мыши содержится в одном из ваших элементов. Если в данный момент не зависает и элемент содержит цель события, установите isHovered true, а если в настоящее время завис и элемент не содержит цель события, установите isHovered false.

This isn ' t полная замена прослушивателей событий enter / leave | over / out, прикрепленных к содержащему div, поскольку я все еще мог воспроизвести крайний случай. Я заметил, что ваш пользовательский интерфейс наиболее подвержен этой проблеме при быстром перемещении мыши и выходе из окна. намного сложнее). Что также, похоже, немного помогло, так это отсутствие определения анонимных функций обратного вызова для div.

import React, { createRef } from "react";

export default class Geo extends React.Component {
  state = {
    isHovering: false
  };
  mouseMoveRef = createRef();

  componentDidMount() {
    window.addEventListener("mousemove", this.checkHover, true);
  }

  componentWillUnmount() {
    window.removeEventListener("mousemove", this.checkHover, true);
  }

  setHover = () => this.setState({ isHovering: true });
  setUnhover = () => this.setState({ isHovering: false });

  checkHover = e => {
    if (this.mouseMoveRef.current) {
      const { isHovering } = this.state;
      const mouseOver = this.mouseMoveRef.current.contains(e.target);
      if (!isHovering && mouseOver) {
        this.setHover();
      }

      if (isHovering && !mouseOver) {
        this.setUnhover();
      }
    }
  };

  render() {
    var textDisplay;

    if (this.state.isHovering) {
      textDisplay = <span>HOVERING</span>;
    } else {
      textDisplay = <h1>NOT HOVERING</h1>;
    }

    return (
      <div
        ref={this.mouseMoveRef}
        onMouseEnter={this.setHover}
        onMouseLeave={this.setUnhover}
        style={{ width: 300, height: 100, background: "green" }}
      >
        {textDisplay}
      </div>
    );
  }
}

Редактировать friendly-chatterjee-xx2ms

0 голосов
/ 03 августа 2020

Насколько я понимаю, у вас проблема с тем, как вы обновляете состояние. Имейте в виду, что React может обновлять состояние асинхронно.

Изменение функции toggleHoverState решит проблему

toggleHoverState() {
    this.setState(state => ({isHovering: !state.isHovering}));
  }

Go на этот раздел в React docs подробнее информация

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...