Sometimes you run into a situation where you want to have
some logic that isn't associated with any rendered output
but starts/stops when a certain page is rendered. React can
handle this by rendering null
and using lifecycle events
to deal with listener attachment and cleanup.
The following code creates two components, one representing
the App and one to handle the logic. App
mounts or
unmounts the KeydownListener
once every second, forcing
componentDidMount
and componentWillUnmount
to fire.
import React, { Component } from "react";import { render } from "react-dom";class KeydownListener extends Component {state = {id: Math.random().toFixed(4)};componentDidMount() {window.document.addEventListener("keydown",this.handleKeyboardNavigation,false);}componentWillUnmount() {window.document.removeEventListener("keydown",this.handleKeyboardNavigation,false);}handleKeyboardNavigation = e => {console.log(`${this.state.id}: caught key event`);};render() {console.log(this.state.id);return null;}}class App extends Component {state = {show: false};componentDidMount() {this.interval = setInterval(() => {this.setState(state => ({...state,show: !state.show}));}, 1000);}componentWillUnmount() {clearInterval(this.interval);}render() {return (<div>{this.state.show && <KeydownListener />}</div>);}}render(<App />, document.getElementById("root"));
The output for the above is the following (which you can test in codesandbox.
0.07050.36640.60170.15000.84280.26680.2668: caught key event0.2668: caught key event0.2668: caught key event0.23280.84420.70640.8180