Удалить прослушиватель событий при отключении

У меня был компонент более высокого порядка, который реагирует так:

export default function (InnerComponent) {
    class InfiniteScrolling extends React.Component {

        constructor(props){
            super(props);
        }

        componentDidMount() {
            window.addEventListener('scroll', this.onScroll.bind(this), false);
        }

        componentWillUnmount() {
            window.removeEventListener('scroll', this.onScroll.bind(this), false);
        }

        onScroll() {
            if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - 50)) {
                const { scrollFunc } = this.props;
                scrollFunc();
            }
        }

        render() {
            return <InnerComponent {...this.props} />;
        }
    }

    InfiniteScrolling.propTypes = {
        scrollFunc: PropTypes.func.isRequired
    };

    return InfiniteScrolling;
}

После размонтирования компонента, который был обернут через InfiniteScrolling, они все еще бросали ошибку (когда я прокручивал):

Предупреждение: setState (...): может обновлять только смонтированный или монтажный компонент. Обычно это означает, что вы вызывали setState() на немонтированном компоненте. Это не-op. Проверьте код для неопределенного компонента.

Несмотря на то, что я удалил событие scroll на моем размонтировании компонентов. Это не сработало.

Но когда я изменил код так:

constructor(props){
    super(props);
    this.onScroll = this.onScroll.bind(this);
}

componentDidMount() {
    window.addEventListener('scroll', this.onScroll, false);
}

componentWillUnmount() {
    window.removeEventListener('scroll', this.onScroll, false);
}

все, кажется, работает нормально, без каких-либо проблем.

Я чувствую, что они точно такие же, но второй отлично работает, в то время как первый из них вызывает ошибку в консоли, как упоминалось ранее!

Ответы

Ответ 1

.bind всегда создает новую функцию, поэтому вам нужно сделать, как показано ниже, поэтому она добавляет и удаляет ту же функцию.

    constructor(props){
        super(props);
        this.onScroll = this.onScroll.bind(this); //bind function once
    }

    componentDidMount() {
        window.addEventListener('scroll', this.onScroll, false);
    }

    componentWillUnmount() {
        // you need to unbind the same listener that was binded.
        window.removeEventListener('scroll', this.onScroll, false);
    }

Ответ 2

      componentDidMount() {
            window.addEventListener('scroll', this.onScroll, false);
        }

        componentWillUnmount() {
            window.removeEventListener('scroll', this.onScroll, false);
        }
        // use arrow function instead
        onScroll = () => { 
            if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - 50)) {
                const { scrollFunc } = this.props;
                scrollFunc();
            }
        }

или вы можете использовать функции Arrow, чтобы решить .bind(this) проблемы, с которыми он работал просто отлично.

Ответ 3

Рабочая версия для моего проекта с функцией стрелки и без привязки:

componentDidMount = () => {
  window.addEventListener("wheel", this.onScroll, false);
};

componentWillUnmount() {
  window.removeEventListener("wheel", this.onScroll, false);
}

onScroll = (e) => {
  const item = this.refs.myElement;
  if (e.deltaY > 0) item.scrollLeft += 200;
  else item.scrollLeft -= 200;
};