From de28197bfa0a5a1cbf3ebc0b7431781430381f40 Mon Sep 17 00:00:00 2001 From: Sergey Melnikov Date: Mon, 4 Jul 2022 12:14:10 -0400 Subject: [PATCH] [react-hooks] initialize Media hooks with correct matches value --- .changeset/four-days-type.md | 5 +++ packages/react-hooks/src/hooks/media.ts | 12 ++++- .../src/hooks/tests/media.test.tsx | 44 ++++++++++++++++++- 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 .changeset/four-days-type.md diff --git a/.changeset/four-days-type.md b/.changeset/four-days-type.md new file mode 100644 index 0000000000..834386ff32 --- /dev/null +++ b/.changeset/four-days-type.md @@ -0,0 +1,5 @@ +--- +'@shopify/react-hooks': major +--- + +Media hooks initialized with correct matches value diff --git a/packages/react-hooks/src/hooks/media.ts b/packages/react-hooks/src/hooks/media.ts index fa0fcaacb7..83391bed20 100644 --- a/packages/react-hooks/src/hooks/media.ts +++ b/packages/react-hooks/src/hooks/media.ts @@ -3,8 +3,16 @@ import {useState, useEffect, useLayoutEffect} from 'react'; type EffectHook = typeof useEffect | typeof useLayoutEffect; function createUseMediaFactory(useEffectHook: EffectHook) { - return (query: string) => { - const [match, setMatch] = useState(false); + return ( + query: string, + {ssr, ssrValue}: {ssr?: boolean; ssrValue?: boolean} = { + ssr: false, + ssrValue: false, + }, + ) => { + const [match, setMatch] = useState(() => + ssr ? Boolean(ssrValue) : window.matchMedia(query).matches, + ); useEffectHook(() => { if (!window || !window.matchMedia) { diff --git a/packages/react-hooks/src/hooks/tests/media.test.tsx b/packages/react-hooks/src/hooks/tests/media.test.tsx index 3e2d90a761..59cbdd8ee6 100644 --- a/packages/react-hooks/src/hooks/tests/media.test.tsx +++ b/packages/react-hooks/src/hooks/tests/media.test.tsx @@ -5,8 +5,11 @@ import {mount} from '@shopify/react-testing'; import {useMedia, useMediaLayout} from '../media'; describe('useMedia and useMediaLayout', () => { + let matches: boolean[] = []; + beforeEach(() => { matchMedia.mock(); + matches = []; }); afterEach(() => { @@ -17,8 +20,17 @@ describe('useMedia and useMediaLayout', () => { ['useMedia', useMedia], ['useMediaLayout', useMediaLayout], ])('%s', (_, useEffectHook) => { - function MockComponent({mediaQuery}: {mediaQuery: string}) { - const matchedQuery = useEffectHook(mediaQuery); + function MockComponent({ + mediaQuery, + ssr = false, + ssrValue = false, + }: { + mediaQuery: string; + ssr?: boolean; + ssrValue?: boolean; + }) { + const matchedQuery = useEffectHook(mediaQuery, {ssr, ssrValue}); + matches.push(matchedQuery); const message = matchedQuery ? 'matched' : 'did not match'; return
{message}
; } @@ -66,6 +78,33 @@ describe('useMedia and useMediaLayout', () => { ); const mockComponent = mount(); + expect(matches).toStrictEqual([true]); + expect(mockComponent.text()).toContain('matched'); + }); + + it('initial render with ssrValue true', () => { + matchMedia.setMedia(() => + mediaQueryList({ + matches: true, + }), + ); + + const mockComponent = mount( + , + ); + expect(matches).toStrictEqual([true]); + expect(mockComponent.text()).toContain('matched'); + }); + + it('initial render with ssrValue false', () => { + matchMedia.setMedia(() => + mediaQueryList({ + matches: true, + }), + ); + + const mockComponent = mount(); + expect(matches).toStrictEqual([false, true]); expect(mockComponent.text()).toContain('matched'); }); @@ -77,6 +116,7 @@ describe('useMedia and useMediaLayout', () => { ); const mockComponent = mount(); + expect(matches).toStrictEqual([false]); expect(mockComponent.text()).toContain('did not match'); });