在Unmount React上删除事件监听器

时间:2016-07-25 09:26:39

标签: javascript reactjs

我有更高级别的组件反应如下:

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()   零件。这是一个无操作。请检查未定义的代码   成分

即使我确实删除了组件卸载上的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);
}
一切似乎都运转良好,没有任何问题。

我觉得它们完全是一样的,但是第二个工作正常,而第一个工作正如前面提到的那样在控制台中抛出错误!

4 个答案:

答案 0 :(得分:64)

您始终在创建新功能

    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);
    }

答案 1 :(得分:1)

      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)正常工作的问题。

答案 2 :(得分:0)

我的项目的带有箭头功能且无绑定的工作版本:

![Alt text](https://g.gravizo.com/source/custom_mark10?https%3A%2F%2Fraw.githubusercontent.com%2FTLmaK0%2Fgravizo%2Fmaster%2FREADME.md)
<details> 
<summary></summary>
custom_mark10
  digraph G {
    size ="4,4";
    main [shape=box];
    main -> parse [weight=8];
    parse -> execute;
    main -> init [style=dotted];
    main -> cleanup;
    execute -> { make_string; printf};
    init -> make_string;
    edge [color=red];
    main -> printf [style=bold,label="100 times"];
    make_string [label="make a string"];
    node [shape=box,style=filled,color=".7 .3 1.0"];
    execute -> compare;
  }
custom_mark10
</details>

答案 3 :(得分:0)

我知道这有点晚了,但是我只是遇到了这个问题,想与您分享我的解决方案,希望得到您的反馈。此解决方案包括react hooks。希望你喜欢

// Declare a static listener.
const eventListeners = useRef();

// now let's create our scroll Handler
const scrollHandler = useCallback(() => {...},[]);

useEffect(() => {
   // Here will be removing the static listener and then updated it for 
   // our new one since the first time will be empty it won't do anything.
    window.removeEventListener('scroll', eventListeners.current, true);

    // Then will set our current scroll handler to our static listener
    eventListeners.current = scrollHandler;

    // Here will be adding the static listener so we can keep the reference
    // and remove it later on
    window.addEventListener('scroll', eventListeners.current, true);
},[scrollHandler]);