I listen for window "scroll" events in one of my ponents. However when the ponent is unmounted, the scroll event listener is not being removed.
The following error is produced when a scroll event occurs after the ponent has been unmounted:
warning.js:36 Warning: setState(...): Can only update a mounted or mounting ponent. This usually means you called setState() on an unmounted ponent. This is a no-op. Please check the code for the TopNavDesktop ponent.
How can I properly remove this event listener?
Example code:
class NavBar extends Component {
constructor() {
super();
this.state = {
distanceScrolled: null
}
}
ponentDidMount() {
window.addEventListener('scroll', this.handleScroll.bind(this));
}
ponentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll.bind(this));
}
handleScroll(e){
const distanceScrolled = e.srcElement.body.scrollTop;
this.setState({ distanceScrolled: distanceScrolled });
}
render { ... }
}
I listen for window "scroll" events in one of my ponents. However when the ponent is unmounted, the scroll event listener is not being removed.
The following error is produced when a scroll event occurs after the ponent has been unmounted:
warning.js:36 Warning: setState(...): Can only update a mounted or mounting ponent. This usually means you called setState() on an unmounted ponent. This is a no-op. Please check the code for the TopNavDesktop ponent.
How can I properly remove this event listener?
Example code:
class NavBar extends Component {
constructor() {
super();
this.state = {
distanceScrolled: null
}
}
ponentDidMount() {
window.addEventListener('scroll', this.handleScroll.bind(this));
}
ponentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll.bind(this));
}
handleScroll(e){
const distanceScrolled = e.srcElement.body.scrollTop;
this.setState({ distanceScrolled: distanceScrolled });
}
render { ... }
}
Share
Improve this question
asked Oct 20, 2016 at 21:53
Don PDon P
63.7k121 gold badges318 silver badges447 bronze badges
2 Answers
Reset to default 12When you remove the listener, you're creating a new function reference.
someFn.bind(this) === someFn.bind(this)
will evaluate to false.
Instead, save the function in your constructor and use that reference:
class NavBar extends Component {
constructor() {
super();
this.state = {
distanceScrolled: null
}
this.scrollFn = this.handleScroll.bind(this);
}
ponentDidMount() {
window.addEventListener('scroll', this.scrollFn);
}
ponentWillUnmount() {
window.removeEventListener('scroll', this.scrollFn);
}
handleScroll(e){
const distanceScrolled = e.srcElement.body.scrollTop;
this.setState({ distanceScrolled: distanceScrolled });
}
render { ... }
}
You should do this in this way:
ponentDidMount() {
this.listener = this.handleScroll.bind(this);
window.addEventListener('scroll', this.listener);
}
ponentWillUnmount() {
window.removeEventListener('scroll', this.listener);
}
By invoking second time this.handleScroll.bind(this)
in ponentWillUnmount
you creating new function instead of passing previous.