From 693e890d44b248eb78a732855d502b235bbb8f4e Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Mon, 24 Feb 2020 11:49:12 +0100 Subject: [PATCH 1/3] fix re-hydration miss-match fixes #7 --- src/index.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 3a063ec..a74aeb7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,9 +3,8 @@ import { useContext, useState, useEffect } from 'react' type MQListEventListener = (this: MediaQueryList, ev: MediaQueryListEvent) => void -type GetCurrentZone = (FullBreakpoints: number[], defaultZone: number) => number -export const getCurrentZone: GetCurrentZone = (bps, defaultZone) => { - if (typeof window === 'undefined') return defaultZone +type GetCurrentZone = (FullBreakpoints: number[]) => number +export const getCurrentZone: GetCurrentZone = (bps) => { const width = window.innerWidth let outZone = bps.findIndex(bp => width < bp) if (outZone < 0) outZone = bps.length @@ -35,9 +34,13 @@ export const ZoneManager: React.FC = ({ children }) => { const bps = [0, ...breakpoints] - const [zone, setZone] = useState(getCurrentZone(bps, defaultZone)) + // SSR renders without calling `useEffect` hooks (thus falling back to `defaultZone`), that's + // why we need to render with the `defaultZone` on the client first to re-hydrate the dom + const [zone, setZone] = useState(defaultZone) useEffect(() => { + setZone(getCurrentZone(bps)) + const listenerForZone = (i: number):MQListEventListener => (e) => { if (!e.matches) return setZone(i) From 8030e7204941791353ea285febd73a28e31d2ded Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Mon, 24 Feb 2020 11:50:11 +0100 Subject: [PATCH 2/3] fix overlapping zones fixes #6 --- src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index a74aeb7..79fb96f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -15,7 +15,7 @@ type GetMediaQueryLists = (FullBreakPoints: number[]) => MediaQueryList[] const getMqLists: GetMediaQueryLists = (bps) => bps.map((bp, i) => { const nextBp = bps[i + 1] return window.matchMedia( - `(min-width: ${bp}px) ${nextBp ? `and (max-width: ${nextBp}px)` : ''}` + `(min-width: ${bp}px) ${nextBp ? `and (max-width: ${nextBp - 1}px)` : ''}` ) }) From 97e439ccc19a2cdc6bc02c7b0047a0447d1ccc0e Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Mon, 24 Feb 2020 11:59:07 +0100 Subject: [PATCH 3/3] prevent re-adding listeners on each render fixes #5 --- src/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index 79fb96f..eb7959d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -57,7 +57,10 @@ export const ZoneManager: React.FC = ({ return () => { mqLists.forEach((mqList, i) => mqList.removeListener(listeners[i])) } - }, [bps]) + }, + + // We use the whole bps array as deps. Using `[bps]` would re-execute `useEffect` on each render + bps) return {children} }