Ben Edelstein Founder @LogRocket, formerly @Google.

Building size-aware React components

2 min read 639

When building React apps, it is sometimes advantageous for components to have awareness of their size and position on screen. This is useful both for rendering content initially, but also for components that need to know when their size changes. Some examples of this are:

  • Components that need to lay out their content differently depending on size. For example, a responsive layout that changes from 1 to 2 columns or a dropdown that switches to a hamburger when it is width-constrained.
  • When using an HTML5 Canvas that has to be re-drawn whenever its size changes
  • When building a layout where the user can adjust the sizes of different panes
  • When using elements or 3rd party libraries that require a known size like react-virtualized, fixed-data-table, etc.
  • When rendering elements with absolute positioning that need their position adjusted when the container size changes.
  • When animating an element’s size with CSS with additional logic that depends on this animated size

Some of these behaviors may be achievable with CSS, or by managing window size with the onResize event, but in the interest of building React components that are maximally reusable, it makes sense to encapsulate this logic into the component itself. That way, regardless of where/how the component is used, it will function correctly.

Luckily there are a few excellent libraries that help solve this problem. Here, I’ll give a brief introduction to each and explain when to use it.

react-measure

react-measure is a helpful library for building size-aware components. It wraps a component and exposes an onResize function that is called with the element’s contentRect (which has bounds and position). This method is called whenever the component’s size or position changes, and can be used to trigger side effects or put the dimensions into state.

This solves most of the earlier examples but there’s one issue — a chicken and egg problem. When the component renders for the first time, its dimensions aren’t always known since its width/height could be determined by its content. As such, we don’t always know the dimensions in the render function, so it’s not entirely possible for the component to have render logic based on its dimensions.

react-sizeme

To solve this problem, we turn to a library called react-sizeme. This library is similar to react-measure but uses a clever solution to solve the aforementioned problem.

react-sizeme does an initial, invisible render of the component to measure its size. It does so in a lightweight way that is less intense than doing a full render of the component. Then, when the component renders, the size is known and the component can render properly from the beginning. Thus, the component can have render logic based on its own dimensions!

Using react-sizeme looks like this:

Caveats

With both of these libraries there are a few caveats to be aware of. The initial render that react-sizeme does to determine the component’s dimensions isn’t free, and does increase the time to visibility of a rendered component. This is not typically noticeable for components that mount once, but with components that mount many times (items in a virtual list, for example) there is a noticeable performance impact. Since react-measure doesn’t do this initial render, it should ideally be used in these cases.

The methods that both libraries use to detect size changes also have a slight latency (~20ms). Usually this feels quite fast, but in practice, I’ve noticed a slight delay in detecting changes which can lead to a component feeling slow.

In general, react-measure has less of a performance impact, so it should be used if possible, but in cases where a component’s initial render depends on its size, then react-sizeme is a good option.

Resources

souporserious/react-measure

Compute measurements of React components. Uses a ResizeObserver to detect when an element’s dimensions have changed. Includes a polyfill for ResizeObserver in unsupported browsers. yarn add react-measure npm install react-measure –save Wrap any child component and calculate its client rect. Adds the following to contentRect.client returned in the child function.

ctrlplusb/react-sizeme

Make your React Components aware of their width and/or height! Blazingly fast. 😛 Responsive Components! Easy to use. Extensive browser support. Supports any Component type, i.e. stateless/class. Really small bundle size. Use it via the render prop pattern (supports children or render prop): Or, via a higher order component: Give your Components the ability to have render logic based on their height and/or width.

 

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, tracking slow network requests and component load time, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors performance of your app with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps - .

Ben Edelstein Founder @LogRocket, formerly @Google.

One Reply to “Building size-aware React components”

  1. Interesting. I’m curious how you would handle SSR? I’m guessing something like pick a default size (mobile?) and render that. Not sure how much has changed in the 2 years since this was written.

    Also it would be nice to link to the libraries.

Leave a Reply