From fc70500b994634a0aa3d79e4d5fdaa1cc531c711 Mon Sep 17 00:00:00 2001 From: Aron Griffis Date: Mon, 27 Jul 2020 11:54:47 -0400 Subject: [PATCH] fix(breakpoints): races in useViewportWidth (#114) The main fix here is changing the initial state from null to window.innerWidth, so that there isn't a useless transition from (for example) `useDown('md') = true` to `useDown('md') = false` when the application loads. Depending on the application, the rerendering penalty can be heavy. While we're here, notice that we can make a couple related changes: First, since the initial state is set properly, we don't need a layout effect, instead we can use a normal effect. Second, swap the order of listener and setWidth to avoid the tiny race between them. --- packages/core/src/breakpoints.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/src/breakpoints.js b/packages/core/src/breakpoints.js index a69a4bc1..97ecba0c 100644 --- a/packages/core/src/breakpoints.js +++ b/packages/core/src/breakpoints.js @@ -31,16 +31,17 @@ function useThemeMaxValue(theme, key) { } export function useViewportWidth() { - const [width, setWidth] = React.useState(null) - - React.useLayoutEffect(() => { - setWidth(window.innerWidth) + const [width, setWidth] = React.useState(typeof window === 'undefined' ? null : window.innerWidth) + React.useEffect(() => { function handleResize() { setWidth(window.innerWidth) } + // Add the listener, then setWidth to avoid race. window.addEventListener('resize', handleResize) + setWidth(window.innerWidth) + return () => window.removeEventListener('resize', handleResize) }, [])