Hooks are a new addition in React 16.8 that lets you use state and other React features without writing a class. This website provides easy to understand code examples to help you learn how hooks work and hopefully inspire you to take advantage of them in your next project. Be sure to check out the official docs. You can also submit post ideas in our Github repo.

If you find yourself adding a lot of event listeners using useEffect you might consider moving that logic to a custom hook. In the recipe below we create a useEventListener hook that handles checking if addEventListener is supported, adding the event listener, and removal on cleanup. See it in action in the CodeSandbox demo.

This hook makes it easy to see which prop changes are causing a component to re-render. If a function is particularly expensive to run and you know it renders the same results given the same props you can use the React.memo higher order component, as we've done with the Counter component in the below example. In this case if you're still seeing re-renders that seem unnecessary you can drop in the useWhyDidYouUpdate hook and check your console to see which props changed between renders and view their previous/current values. Pretty nifty huh?

import{ useState, useEffect, useRef }from'react';// Let's pretend this <Counter> component is expensive to re-render so ...// ... we wrap with React.memo, but we're still seeing performance issues :/// So we add useWhyDidYouUpdate and check our console to see what's going on.const Counter = React.memo(props =>{useWhyDidYouUpdate('Counter', props);return<div style={props.style}>{props.count}</div>;});functionApp(){const[count, setCount]=useState(0);const[userId, setUserId]=useState(0);// Our console output tells use that the style prop for <Counter> ...// ... changes on every render, even when we only change userId state by ...// ... clicking the "switch user" button. Oh of course! That's because the// ... counterStyle object is being re-created on every render.// Thanks to our hook we figured this out and realized we should probably ...// ... move this object outside of the component body.const counterStyle ={
fontSize:'3rem',
color:'red'};return(<div><div className="counter"><Counter count={count} style={counterStyle}/><button onClick={()=>setCount(count +1)}>Increment</button></div><div className="user"><img src={`http://i.pravatar.cc/80?img=${userId}`}/><button onClick={()=>setUserId(userId +1)}>Switch User</button></div></div>);}// HookfunctionuseWhyDidYouUpdate(name, props){// Get a mutable ref object where we can store props ...// ... for comparison next time this hook runs.const previousProps =useRef();useEffect(()=>{if(previousProps.current){// Get all keys from previous and current propsconst allKeys = Object.keys({...previousProps.current,...props });// Use this object to keep track of changed propsconst changesObj ={};// Iterate through keys
allKeys.forEach(key =>{// If previous is different from currentif(previousProps.current[key]!== props[key]){// Add to changesObj
changesObj[key]={from: previousProps.current[key],
to: props[key]};}});// If changesObj not empty then output to consoleif(Object.keys(changesObj).length){
console.log('[why-did-you-update]', name, changesObj);}}// Finally update previousProps with current props for next hook call
previousProps.current = props;});}

This hook handles all the stateful logic required to add a ☾ dark mode toggle to your website. It utilizes localStorage to remember the user's chosen mode, defaults to their browser or OS level setting using the prefers-color-scheme media query and manages the setting of a .dark-mode className on body to apply your styles.

This post also helps illustrate the power of hook composition. The syncing of state to localStorage is handled by our useLocalStorage hook. Detecting the user's dark mode preference is handled by our useMedia hook. Both of these hooks were created for other use-cases, but here we've composed them to create a super useful hook in relatively few lines of code. It's almost as if hooks bring the compositional power of React components to stateful logic! 🤯

// UsagefunctionApp(){const[darkMode, setDarkMode]=useDarkMode();return(<div><div className="navbar"><Toggle darkMode={darkMode} setDarkMode={setDarkMode}/></div><Content /></div>);}// HookfunctionuseDarkMode(){// Use our useLocalStorage hook to persist state through a page refresh.// Read the recipe for this hook to learn more: usehooks.com/useLocalStorageconst[enabledState, setEnabledState]=useLocalStorage('dark-mode-enabled');// See if user has set a browser or OS preference for dark mode.// The usePrefersDarkMode hook composes a useMedia hook (see code below).const prefersDarkMode =usePrefersDarkMode();// If enabledState is defined use it, otherwise fallback to prefersDarkMode.// This allows user to override OS level setting on our website.const enabled =typeof enabledState !=='undefined'? enabledState : prefersDarkMode;// Fire off effect that add/removes dark mode classuseEffect(()=>{const className ='dark-mode';const element = window.document.body;if(enabled){
element.classList.add(className);}else{
element.classList.remove(className);}},[enabled]// Only re-call effect when value changes);// Return enabled state and setterreturn[enabled, setEnabledState];}// Compose our useMedia hook to detect dark mode preference.// The API for useMedia looks a bit weird, but that's because ...// ... it was designed to support multiple media queries and return values.// Thanks to hook composition we can hide away that extra complexity!// Read the recipe for useMedia to learn more: usehooks.com/useMediafunctionusePrefersDarkMode(){returnuseMedia(['(prefers-color-scheme: dark)'],[true],false);}

📚 Also check out:

donavon/use-dark-mode - A more configurable implementation of this hook that syncs changes across browser tabs and handles SSR. Provided much of the code and inspiration for this post.

This hook makes it super easy to utilize media queries in your component logic. In our example below we render a different number of columns depending on which media query matches the current screen width, and then distribute images amongst the columns in a way that limits column height difference (we don't want one column way longer than the rest).

You could create a hook that directly measures screen width instead of using media queries, but this method is nice because it makes it easy to share media queries between JS and your stylesheet. See it in action in the CodeSandbox Demo.

Sometimes you want to prevent your users from being able to scroll the body of your page while a particular component is absolutely positioned over your page (think modal or full-screen mobile menu). It can be confusing to see the background content scroll underneath a modal, especially if you intended to scroll an area within the modal. Well, this hook solves that! Simply call the useLockBodyScroll hook in any component and body scrolling will be locked until that component unmounts. See it in action in the CodeSandbox Demo.

This hook makes it easy to dynamically change the appearance of your app using CSS variables. You simply pass in an object containing key/value pairs of the CSS variables you'd like to update and the hook updates each variable in the document's root element. This is useful in situations where you can't define styles inline (no pseudo class support) and there are too many style permutations to include each theme in your stylesheet (such as a web app that lets users customize the look of their profile). It's worth noting that many css-in-js libraries support dynamic styles out of the box, but it's interesting to experiment with how this can be done with just CSS variables and a React Hook. The example below is intentionally very simple, but you could imagine the theme object being stored in state or fetched from an API. Be sure to check out the CodeSandbox demo for a more interesting example and to see the accompanying stylesheet.

This hook is part of the react-spring animation library which allows for highly performant physics-based animations. I try to avoid including dependencies in these recipes, but once in awhile I'm going to make an exception for hooks that expose the functionality of really useful libraries. One nice thing about react-spring is that it allows you to completely skip the React render cycle when applying animations, often giving a pretty substantial performance boost. In our recipe below we render a row of cards and apply a springy animation effect related to the mouse position over any given card. To make this work we call the useSpring hook with an array of values we want to animate, render an animated.div component (exported by react-spring), get the mouse position over a card with the onMouseMove event, then call setAnimatedProps (function returned by the hook) to update that set of values based on the mouse position. Read through the comments in the recipe below for more details or jump right over to the CodeSandbox demo. I liked this effect so much I ended up using it on my startup's landing page 😎

This hook makes it really easy to add undo/redo functionality to your app. Our recipe is a simple drawing app. It generates a grid of blocks, allows you to click any block to toggle its color, and uses the useHistory hook so we can undo, redo, or clear all changes to the canvas. Check out our CodeSandbox demo. Within our hook we're using useReducer to store state instead of useState, which should look familiar to anyone that's used redux (read more about useReducer in the official docs). The hook code was copied, with minor changes, from the excellent use-undo library, so if you'd like to pull this into your project you can also use that library via npm.

This hook makes it super easy to dynamically load an external script and know when its loaded. This is useful when you need to interact with a 3rd party library (Stripe, Google Analytics, etc) and you'd prefer to load the script when needed rather then include it in the document head for every page request. In the example below we wait until the script has loaded successfully before calling a function declared in the script. If you're interested in seeing how this would look if implemented as a Higher Order Component then check out the source of react-script-loader-hoc. I personally find it much more readable as a hook. Another advantage is because it's so easy to call the same hook multiple times to load multiple different scripts, unlike the HOC implementation, we can skip adding support for passing in multiple src strings.

This hook makes it easy to detect when the user is pressing a specific key on their keyboard. The recipe is fairly simple, as I want to show how little code is required, but I challenge any readers to create a more advanced version of this hook. Detecting when multiple keys are held down at the same time would be a nice addition. Bonus points: also require they be held down in a specified order. Feel free to share anything you've created in this recipe's gist.