levraininjaneer
levraininjaneer

Reputation: 1377

react js eventListeners not removed as expected

I am working on a react web application that consists of several pages. I've set up a react router that switches between the pages.

Something like:

render((
    <Provider store={store}>
        <BrowserRouter>
            <Switch>
                <Route exact path='/' component={RedirectPage} />
                <Route exact path='/sign-in' render={() => <PlayerSelect />}/>
                <Route exact path='/most-recent-scenario' render={() => <ScenarioInterface />} />
                <Route exact path='/home' render={() => <Home />} />
                <Route exact path='/scenario/:id' render={props => <Index {...props} /> } />
                <Route exact path='/user-select' render={() => <UserSelect />}/>
            </Switch>
        </BrowserRouter>
    </Provider>
), document.getElementById('root'));

On the pages themselves, I make use of react-router Redirect function to navigate to and fro. Something like:

import { Redirect} from 'react-router-dom'

class Index extends React.Component {
  state = {
    ...
    redirect: false,
    redirect_to: ""
  }

  setRedirect = (page) => {
      this.setState({
      redirect: true,
      redirect_to: page})
  }

  renderRedirect = () => {
  if (this.state.redirect) {
      return <Redirect to={this.state.redirect_to} /> }
  }

  render(){
    return (
        <div className={classes.root}>
          {this.renderRedirect()}
          ...

This all works. However, on the one page, I use some key bindings.

I've learnt that the best way to assign key bindings is to do it when the component is created, like <MyWebpage onKeyDown={handleKeyDown} />, but because of legacy reasons, that not easy for me and currently I do the key-bindings with :

  componentDidMount(){
    document.addEventListener("keydown", this.handleKeyDown.bind(this));
    document.addEventListener("keyup", this.handleKeyUp.bind(this));}

  componentWillUnmount(){
    document.removeEventListener("keydown", this.handleKeyDown.bind(this));
    document.removeEventListener("keyup", this.handleKeyUp.bind(this));}

I find that handleKeyDown is still being called, even after I've navigated to another page. I've checked: componentWillUnmount is called and executed.

So I'd like to figure out why my removeEventListener is not working and how to fix them.

Upvotes: 1

Views: 603

Answers (3)

falinsky
falinsky

Reputation: 7428

You should remove the same listener which you add. So I suggest to create a final version bound to this in constructor and manipulate with it in lifecycle callbacks:

  .....

  constructor(props) {
    super(props);

    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleKeyUp = this.handleKeyUp.bind(this);
  }

  componentDidMount() {
    document.addEventListener("keydown", this.handleKeyDown);
    document.addEventListener("keyup", this.handleKeyUp);
  }

  componentWillUnmount() {
    document.removeEventListener("keydown", this.handleKeyDown);
    document.removeEventListener("keyup", this.handleKeyUp);
  }

  .....

Upvotes: 3

sagi
sagi

Reputation: 40481

You should bind the methods inside the constructor. AddEventListener and RemoveEventListener should recieve the same instances of a method in order to work , and I suspect that binding returns a new “binded” method , so they doesn’t match .

After binding the methods in the Ctor , just pass then to the event handling , they will already be binded

Upvotes: 2

Sakhi Mansoor
Sakhi Mansoor

Reputation: 8102

You have to pass the same function as the second parameter to the addEventListener/removeEventListener from global window variable: That same goes for addEventLsitener:

componentDidMount () {
  window.addEventListener("keydown", this.handleKeyDown);
}


componentWillUnmount(){
     window.removeEventListener("keydown", this.handleKeyDown);
     window.removeEventListener("keyup", this.handleKeyUp);
    }

Upvotes: 0

Related Questions