How to Rerender Component on Resize in React

How to Rerender Component on Resize in React

With the help of hooks and event listeners
Ferenc Almasi β€’ 2023 May 15 β€’ Read time 7 min read
Learn how you can use the useEffect hook in React to re-render components when a resize occurs.
  • twitter
  • facebook
React

When working with complex UIs in React, such as a masonry layout, you may need to adjust the display and position of elements based on the available screen size. In such cases, we need to re-render components when the screen is resized. 

In this tutorial, we will take a look at how you can re-render components when the screen is resized and how you can create a custom hook to reuse this functionality elsewhere in your application.


Rerender on Resize with useEffect

To re-render a component on screen resize, we need to introduce a useEffect hook that attaches a resize event listener to the document:

Copied to clipboard! Playground
import React, { useState, useEffect } from 'react'

const App = () => {
    const [size, setSize] = useState({
        width: window.innerWidth,
        height: window.innerHeight
    })

    useEffect(() => {
        const resize = () => {
            setSize({
                width: window.innerWidth,
                height: window.innerHeight
            })
        }

        window.addEventListener('resize', resize)
    }, [])

    return (
        <h1>Your screen size is: {size.width}x{size.height}</h1>
    )
}

export default App
App.jsx
Re-rendering component on resize

The above example works in the following way:

  • Line 4: We create a new state using the useState hook.
  • Line 9: We add a useEffect hook that will be triggered when the component is mounted to the DOM. The reason this is triggered on mount is that the hook has an empty dependency array as the second parameter.
  • Line 10: We create a resize function that calls the setSize updater function with the updated values for the screen size.
  • Line 17: We attach this function to the resize event using window.addEventListener.

The dependency array tells React when the useEffect should run. An empty array means it has no dependencies, so it will only run once when the component is mounted.

Cleaning up the resize on unmount

This works perfectly; however, there are some improvements that we can make. Currently, the event listener remains attached to the DOM even if the component is unmounted. This can cause performance issues and potentially bugs.

To resolve this, return a function from the useEffect hook that will be called when the component is unmounted:

Copied to clipboard! Playground
useEffect(() => {
    const resize = () => {
        setSize({
            width: window.innerWidth,
            height: window.innerHeight
        })
    }

    window.addEventListener('resize', resize)

    return () => {
        window.removeEventListener('resize', resize)
    }
}, [])
App.jsx
Add the return function to the useEffect hook

Adding Debounce to Improve Performance

This solution, however, has a big downside. It affects performance as the resize event is being called on each pixel change. This results in a lot of unnecessary calls and redraws.

We can optimize this by introducing a debounce function. This ensures that the resize function is only called once every x milliseconds. Add the following function to your application:

Copied to clipboard! Playground
const useDebounce = (func, milliseconds) => {
    const time = milliseconds || 400
    let timer

    return event => {
        if (timer) {
            clearTimeout(timer)
        }

        timer = setTimeout(func, time, event)
    }
}

export default useDebounce
useDebounce.js
Create the useDebounce function

This function works by delaying the execution of the passed function using a setTimeout, with a default delay of 400 milliseconds. Notice that we can pass the original event through by using the third parameter of the setTimeout function. To use it, wrap the resize function with the useDebounce function in the following way:

Copied to clipboard! Playground
// Don't forget to import useDebounce at the top of the file
import useDebounce from './useDebounce'

useEffect(() => {
    const resize = useDebounce(() => {
        setSize({
            width: window.innerWidth,
            height: window.innerHeight
        })
    })

    window.addEventListener('resize', resize)

    return () => {
        window.removeEventListener('resize', resize)
    }
}, [])
App.jsx
Wrap the resize function with useDebounce

Now, whenever we resize the window, the function will only be triggered if there are no new events for 400 milliseconds. This greatly reduces the number of function calls.

Looking to improve your skills? Check out our interactive course to master React from start to finish.
Master Reactinfo Remove ads

Creating a Custom useResize Hook

To make this functionality reusable, we can take this code one step further and create a custom React hook. Extract the useState and useEffect hooks into a separate function that returns the value from the useState hook:

Copied to clipboard! Playground
import { useState, useEffect } from 'react'
import useDebounce from './useDebounce'

const useResize = () => {
    const [size, setSize] = useState([window.innerWidth, window.innerHeight])

    useEffect(() => {
        const resize = useDebounce(() => {
            setSize([
                window.innerWidth,
                window.innerHeight
            ])
        })

        window.addEventListener('resize', resize)

        return () => {
            window.removeEventListener('resize', resize)
        }
    }, [])

    return size
}

export default useResize
useResize.jsx
Create the useResize function

Unlike the previous example, this hook uses an array for the state. The reason for this is that we can destructure both width and height into variables when we need to use this hook inside a component.

Make sure to return the size state variable at the end of the useResize hook.

To use the hook in a component, simply import it and destructure the returned array into width and height variables:

Copied to clipboard! Playground
import useResize from './useResize'

const App = () => {
    const [width, height] = useResize()

    return (
        <h1>Your screen size is: {width}x{height}</h1>
    )
}
App.jsx
Using the useResize hook in components

Summary

In summary, when working with resize event listeners, make sure you always debounce them to prevent any performance bottlenecks. Also, don't forget to remove the event listener during the unmount phase to clean up the application from unnecessary event listeners.

If you are interested in learning more about React, be sure to check out our guided roadmap below. Do you have any questions that this tutorial did not cover? Let us know in the comments below! Thank you for reading, Happy coding! πŸ‘¨β€πŸ’»

Master React
  • twitter
  • facebook
React
Did you find this page helpful?
πŸ“š More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access 100+ interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Prepare for technical interviews
Become a Pro

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.