April 20: Intervals and event listeners when working with React hooks

© 1999 United Plankton Pictures and Nickelodeon Animation Studios — all rights reserved

Background: Boogie with the Hook

export default function Timer( { currentTime } ) {   return <div className="timer">
<span>{ Math.floor( currentTime / 60 ) }</span>
:
<span>{ ( "0" + ( currentTime % 60 ) ).slice( -2 ) }</span>
</div>;
}

Sounds great…but there’s a catch, right?

import { useState } from "react";export default function Timer() {   const [ currentTime, setCurrentTime ] = useState( 240 );   function tick() {
if ( !!currentTime ) setCurrentTime( currentTime - 1 );
}
setInterval( tick, 1000 ); return <div className="timer">
<span>{ Math.floor( currentTime / 60 ) }</span>
:
<span>{ ( "0" + ( currentTime % 60 ) ).slice( -2 ) }</span>
</div>;
}
export default function App() {...function handleKeyPress( keyPressEvent ) { ... }window.addEventListener( "keydown", handleKeyPress );return <div className="app">
...
</div>;
}

Still living with the side effects

  • a callback function defining the behavior to hook; and
  • an array of dependencies: functions or variables within the component’s scope which may change as a result of the hook’s execution
import { useEffect, useState } from 'react';export default function Timer() {const [ currentTime, setCurrentTime ] = useState( 240 );function tick() {
if ( !!currentTime ) setCurrentTime( currentTime - 1 );
}
useEffect( () => {
const timer = setInterval( tick, 1000 );
return () => clearInterval( timer );
}, [ tick ] );
return <div className="timer">
<span>{ Math.floor( currentTime / 60 ) }</span>
:
<span>{ ( "0" + ( currentTime % 60 ) ).slice( -2 ) }</span>
</div>;
}
  1. The tick() function is included as a dependency of the useEffect hook, because its use creates a side effect that changes the component’s state (hence the name);
  2. The useEffect must return a function that calls clearInterval, so a new tick() interval isn’t created upon every re-render.
The ‘tick’ function makes the dependencies of useEffect Hook (at line 7) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of ‘tick’ in its own useCallback() Hook
import { useCallback, useEffect, useState } from 'react';export default function Timer() {const [ currentTime, setCurrentTime ] = useState( 240 );const tick = useCallback( () => {
if ( !!currentTime ) setCurrentTime( currentTime - 1 );
}, [ currentTime, setCurrentTime ] );
useEffect( () => {
const timer = setInterval( tick, 1000 );
return () => clearInterval( timer );
}, [ tick ] );
return <div className="timer">
<span>{ Math.floor( currentTime / 60 ) }</span>
:
<span>{ ( "0" + ( currentTime % 60 ) ).slice( -2 ) }</span>
</div>;
}
import { useCallback, useEffect, useState } from 'react';export default function App() {...const handleKeyPress = useCallback( keyPressEvent => {
...
}, [ ... ] );
useEffect( () => {
window.addEventListener( "keydown", handleKeyPress );
return () => window.removeEventListener( "keydown", handleKeyPress );
}, [ handleKeyPress ] );
return <div className="app">
...
</div>;
}

Conclusion

--

--

--

Oh geez, Josh Frank decided to go to Flatiron? He must be insane…

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How Does JavaScript’s curry() Actually Work?

How to use Wikipedia’s search API to build a user interface with RamdaJS

https://youtu.be/-JI4qa1XNqM

Migrating React table from v6 to v7

Building CI/CD for React Static Web Apps Service Using Azure DevOps

Migrate From nodebrew to nvm

Adding Push Notifications to a Web App

How to add text colour in Contentful’s Rich Text

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Josh Frank

Josh Frank

Oh geez, Josh Frank decided to go to Flatiron? He must be insane…

More from Medium

Tips to build a Todo app with react, redux-saga, typescript and react-bootstrap — 1

Todo app with react + typescript + react-saga

Introduction Of React Hook

A pagination state management with useReducer

Building a simple Colour Picker in React from scratch