evoach Chatbot Builder
evoach Chatbot Builder

Handle window resizing with a React context

Christian Mähler
3 min readMar 4, 2022

--

Optimal layouts automatically adapt to different screen sizes and window size changes automatically, they behave like a “responsive” component. In some cases, you may want to get the current width and height of a tab for your React component — or for more than one component.

The traditional way to handle such resizing events is to add an event listener and catch the “resize” event like this:

add a simple event handler

Of course, you can use the real event type instead of “any” in your actual implementation. You can find more information about the window resize event here: https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event.

If you want to get notified about changes in your React component, you may use a code snippet like this:

useEffect(() => {

const handleResize = () => {
// do magic for resize
}

window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};

}, []);

useEffect with empty dependency array means that the event listener is attached once after the component was rendered the first time. The return statement would trigger if a re-render occurs (we need that below). If you add some functions in handleResize, you have to add them to the dependency array.

Of course, you can add this snippet in every component that intends to subscribe to the window size change. But in that case, you may copy code several times, violating the DRY principle.

The solution in the React world could be a context that provides all necessary information. Let’s assume that you want to subscribe to the current width and height and keep it updated every time the window size changes. When using a context, the subscription to the width/height in your React component should look similar to this one:

const { clientHeight, clientWidth } = useContext(WindowContext);

The question is: how can you implement the WindowContext? Here comes how it may look like:

import React, { useCallback, useEffect, useState } from 'react';export type WindowContextProps = {
clientHeight: number;
clientWidth: number;
};
export const WindowContext = React.createContext<WindowContextProps>({ clientHeight: 0, clientWidth: 0, });export const WindowContextProvider: React.FC = ({ children }) => {const getVh = useCallback(() => {
return Math.max(
document.documentElement.clientHeight || 0,
window.innerHeight || 0
);
}, []);
const getVw = useCallback(() => {
return Math.max(
document.documentElement.clientWidth || 0,
window.innerWidth || 0
);
}, []);
const [clientHeight, setVh] = useState<number>(getVh());
const [clientWidth, setVw] = useState<number>(getVw());
useEffect(() => {
const handleResize = () => {
setVh(getVh());
setVw(getVw());
}
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [getVh, getVw]);
return (
<WindowContext.Provider value={{ clientHeight, clientWidth, }} >
{children}
</WindowContext.Provider>
);
};

Let me explain: this implements a React Context named “WindowContext”. The context subscribes to window resizing events and when these events happen, it provides the current clientHeight and the clientWidth in the context. getVh and getVw extract the current height and width which is stored in the state of the context by calling setVh and setVw.

In the next step, you have to make the context available for your app, e.g. like this in your App.tsx:

... 
<WindowContextProvider>
<AppLayout>
<AppRouter />
</AppLayout>
</WindowContextProvider>
...

After these preparations, each component below that context, i.e., “below” AppLayout and AppRouter, can access clientWidth and clientHeight as described above with:

const { clientHeight, clientWidth } = useContext(WindowContext);

With that approach, you don’t have to add an event listener in each component. Of course, you may enhance the WindowContext provider with all the information you need or even with helper functions that are then provided to each subscribing component.

I hope, this context approach is useful for you. If there are better approaches to handle my use case of catching resizing events in several React components, feel free to leave a comment below. Thanks!

UPDATE Feb 2023: you may use your new Context Provider to replace the Javascript window.alert with your own component in React!

--

--

Christian Mähler

Passionate about software development. Pragmatic and enthusiastic.