Правильное удаление обработчика событий после размонтирования компонента - PullRequest
0 голосов
/ 13 мая 2019

Я пытаюсь реализовать HOC, который размонтирует компонент, если пользователь щелкнет снаружи. Вот мой HOC ClickOutsideHOC.js

import React from 'react'

const ClickOutsideHOC = props => {

const {
    callback,
    identifier
} = props

React.useEffect(() => {
    document.addEventListener('click', handleDOMClickHOC(identifier, callback))
    return () => document.removeEventListener('click', handleDOMClickHOC) //  this needs repair
}, [])

    return props.children
}

const handleDOMClickHOC = (identifier, callback) => event => {
    const elem = document.querySelector(identifier)
    if (elem && !elem.contains(event.target))
        callback(false)
}
export default ClickOutsideHOC`

Вот как я использую HOC. SomeOtherComponent.js

const [toggleValue, setToggleValue] = React.useState(false)
//
//
//
{
    toggleValue ? 
    <ClickOutsideHOC
        identifier=".some-class-name"
        callback={setToggleValue}
    >
        <div className="some-class-name">
        </div>
    </ClickOutsideHOC>: ''
}

Кажется, это работает. Проблема в том, что я не уверен в процедуре удаления обработчика событий. Функция handleDOMClickHOC возвращает ссылку на новую функцию, которую я нигде не храню. Я думаю, что это приведет к утечке памяти. На вкладке Event Listeners консоли отладчика Chrome я вижу, что в DOM зарегистрированы несколько обработчиков. Как я могу написать это так, чтобы не было утечки памяти из-за неподписанных обработчиков событий?

Ответы [ 2 ]

1 голос
/ 07 июня 2019

Итак, если вы знаете, что вам нужна ссылка, чтобы удалить слушателя, почему бы не создать его?

import React from 'react'

const handleDOMClickHOC = (identifier, callback) => event => {
  const elem = document.querySelector(identifier)
  if (elem && !elem.contains(event.target))
    callback(false)
}

const ClickOutsideHOC = props => {

  const {
    callback,
    identifier
  } = props

  const listener = handleDOMClickHOC(identifier, callback);

  React.useEffect(() => {
    document.addEventListener('click', listener)
    return () => document.removeEventListener('click', listener)
  }, [])

  return props.children
}
export default ClickOutsideHOC`
0 голосов
/ 13 мая 2019

Вы можете просто связать все необходимые аргументы с помощью call:

Таким образом вы всегда будете передавать событие, аргументы и другие вещи в Handler.

React.useEffect(() => {
    document.addEventListener('click', handleDOMClickHOC.call(null, identifier, callback) } )
    return () => document.removeEventListener('click', handleDOMClickHOC) //  this needs repair
}, [])
...