UseEffect не показывает ошибку для несуществующего прослушивателя событий при очистке

Итак, согласно документации React, исходное состояние приведенного ниже кода canMove истинно. Я изменил его на ложь.

import React from "react";
import "./style.css";
import { useState, useEffect } from 'react';

export default function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  const [canMove, setCanMove] = useState(false);

  useEffect(() => {
    function handleMove(e) {
      setPosition({ x: e.clientX, y: e.clientY });
    }
    if (canMove)
      window.addEventListener('pointermove', handleMove);

    return () => window.removeEventListener('pointermove', handleMove);
  }, [canMove]);

  return (
    <>
      <label>
        <input type = "checkbox"
          checked = {canMove}
          onChange = {(e) => {
            setCanMove(e.target.checked)
            }
          } 
        />
        The dot is allowed to move
      </label>
      <hr />
      <div style = {{
        position: 'absolute',
        backgroundColor: 'pink',
        borderRadius: '50%',
        opacity: 0.6,
        transform: `translate(${position.x}px, ${position.y}px)`,
        pointerEvents: 'none',
        left: -20,
        top: -20,
        width: 40,
        height: 40,
      }} />
    </>
  );
}

Таким образом, после первого рендеринга useEffect запускается, но добавление прослушивателя событий в "pointermove" зависит от canMove, что теперь является ложным, и, следовательно, прослушиватель событий не добавляется. Теперь, если мы установим флажок canMove true, это снова активирует useEffect, и сначала должна запуститься очистка. Но ранее не было добавлено функции handlemove для перемещения указателя. Значит, эта строка логически должна выдавать ошибку?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Постановка в очередь удаления прослушивателя событий не является ошибкой... если он существует, он будет удален, в противном случае он игнорируется. См. EventTarget: RemoveEventListener:

Вызов removeEventListener() с неидентифицирующими аргументами любой зарегистрированный в настоящее время прослушиватель событий на EventTarget не имеет эффект.

Это означает, что ваш текущий/исходный код в порядке, ошибка не должна возникать, поскольку прослушиватель событий не был добавлен ранее.

так почему этот фрагмент кода не работает. `const [canMove, setCanMove] = useState(true); useEffect(() => { if (!canMove) window.removeEventListener('pointermove', handleMove); if (canMove){ function handleMove(e) { setPosition({ x: e.clientX, y: e.clientY }) ; } window.addEventListener('pointermove', handleMove } }, [canMove]); `остальная часть кода такая же. Здесь useEffect запускается и добавляет handleMove к pointermove.

Indra 29.07.2024 11:37

Когда canMove меняется на false, выполняется первое условие, новый handleMove все еще не определен, а раньше handleMove уже добавлен в pointermove, так почему его удаление приводит к ошибке.

Indra 29.07.2024 11:38

@Индра Извините, вы видите какую-то ошибку? В своем посте вы сказали, что его нет, но по какой-то причине вы его ждали. Однако в своем первом комментарии вы пытаетесь ссылаться на handleMove до того, как он будет объявлен, и на самом деле он объявлен в другой области JavaScript, то есть в области действия if-блока. Вероятно, это сработало бы, если бы вы переместили объявление handleMove в начало функции обратного вызова useEffect, как в вашем посте.

Drew Reese 29.07.2024 18:14

Да, в моем первом комментарии. Я только что удалил очистку и добавил обе в настройку useEffect. Моя идея заключалась в том, что если handleMove добавляется к прослушивателю событий, когда useEffect запускается изначально, а затем canMove становится ложным, тогда он переходит к первому блоку if и сталкивается с необходимостью удалить handleMove, который уже добавлен в pointermove. Я ожидаю, что это сработает, поскольку, когда canMove истинно, он не переходит в блок if, где определен handleMove. И я прошу JS просто удалить функцию handleMove, которая была добавлена ​​ранее.

Indra 29.07.2024 18:50

@Indra Эта версия ошибочна, поскольку теперь вы опускаете функцию очистки, чтобы удалить прослушиватель событий при размонтировании компонента и перед применением каких-либо новых эффектов. Я не думаю, что есть какие-либо проблемы с кодом, который у вас есть в вашем сообщении. Вы имеете в виду, что у вас есть какие-то проблемы с этим или он работает не так, как вы ожидаете? Он добавляет прослушиватель событий, когда canMove имеет значение true, и возвращает функцию очистки для удаления любого добавленного прослушивателя.

Drew Reese 29.07.2024 18:53

нет, я имею в виду не код в вопросе, а это

Indra 29.07.2024 19:03

@Индра Хорошо, это проблема, которую я описал, на которую вы пытаетесь ссылаться handleMove, прежде чем она будет объявлена. Перемещение handleMove вверх устраняет эту проблему, но удаление по-прежнему не работает по другой причине, которую я описал. Тем не менее, когда я редактирую эту песочницу в соответствии с кодом, который есть в вашем сообщении, пользовательский интерфейс работает так, как я думаю, вы и намереваетесь. Когда флажок «можно перемещать» снят, точка прилипает и не перемещается, а когда флажок установлен, точка следует за мышью.

Drew Reese 29.07.2024 19:07

Но перемещение handleMove вверх совершенно не решает проблему. Можете ли вы поделиться ссылкой.

Indra 29.07.2024 19:23

@Индра, я не очень знаком со stackblitz, но вот ваш отредактированный код в работающем кодах и ящике. Однако, как я уже сказал, перемещение handleMove в начало обратного вызова эффекта устраняет только проблему со ссылкой, но все еще остается проблема очистки эффекта для удаления всех ранее добавленных прослушивателей, которая не работает. Использование правильной возвращаемой функции очистки устраняет такие проблемы, например. код в вашем посте. Я неправильно понимаю ваш пост/вопрос?

Drew Reese 29.07.2024 19:29

Понятно. Но предположим, что очистка отсутствует: (В моем коде SB) -изначально canMove имеет значение true => прослушиватель handleMove добавлен в poinetermove. - для последующих рендеров (только из-за setPosition) код useEffect не запускается. -теперь canMove меняется на false => нет очистки в коде => установка запускается => если блок, когда canMove имеет значение false, запускается => handleMove все еще не определен в этом рендеринге (поскольку элемент управления не достигает этого конкретного блока if) => сейчас мы пытаемся удалить существующий добавленный handleMove. - почему это не работает?

Indra 29.07.2024 19:41

Давайте продолжим обсуждение в чате.

Drew Reese 29.07.2024 20:22

Я ответил на твой последний чат

Indra 01.08.2024 18:01

@Индра В чате? Кажется, у меня последний комментарий в чате.

Drew Reese 01.08.2024 18:05

Другие вопросы по теме