Skip to content

Commit

Permalink
[@mantine/hooks] Add initial value support to use-color-scheme and us…
Browse files Browse the repository at this point in the history
…e-reduced-motion docs
  • Loading branch information
rtivital committed Apr 17, 2022
1 parent 49ef929 commit 61b8042
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 20 deletions.
8 changes: 7 additions & 1 deletion docs/src/docs/hooks/use-color-scheme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ use-color-scheme returns color scheme value i.e. either `dark` or `light`:

Hook uses [use-media-query](/hooks/use-media-query/) hook under the hood.
Hook relies on `window.matchMedia()` [API](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
and will always return `light` if the api is not available (e.g. during server side rendering).
and will always return `light` if the api is not available (e.g. during server side rendering) unless initial value is provided in first argument.

## Definition

```tsx
function useColorScheme(initialValue?: 'dark' | 'light'): 'dark' | 'light';
```
21 changes: 13 additions & 8 deletions docs/src/docs/hooks/use-media-query.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,21 @@ import { HooksDemos } from '@mantine/demos';
## Usage

use-media-query hook allows to subscribe to media queries.
It receives media query as an argument and returns true
if given media query matches current state.
It receives media query as an argument and returns true if given media query matches current state.
Hook relies on `window.matchMedia()` [API](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
and will return false if api is not available.
and will return false if api is not available unless initial value is provided in the second argument.

Hook takes media query as first argument and returns true if query is satisfied.
Resize browser window to trigger `window.matchMedia` event:

<Demo data={HooksDemos.useMediaQueryDemo} />

## Server Side Rendering
When rendering a component on the server that uses useMediaQuery, it is important to pass the second argument `initialValue` because without it the server may generate html that the React client cannot correctly hydrate.
See the [React docs](https://reactjs.org/docs/react-dom.html#hydrate) for more on why this is can lead to costly bugs.

When rendering a component on the server that uses useMediaQuery, it is important to pass the second argument `initialValue`,
without it the server may generate html that cannot be correctly hydrated on client.

For example, the server will generate the html for clients using a smaller device.
After the React client hydrates this, the hook will render again and return the result of the media query:
After the hydration, the hook will render again and return the result of the media query:

```tsx
import { Badge } from '@mantine/core';
Expand All @@ -46,4 +45,10 @@ function Demo() {
</Badge>
);
}`
```
```

## Definition

```tsx
function useMediaQuery(query: string, initialValue?: boolean): boolean;
```
8 changes: 7 additions & 1 deletion docs/src/docs/hooks/use-reduced-motion.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ import { HooksDemos } from '@mantine/demos';
use-reduced-motion detects if user [prefers to reduce motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).
It uses [use-media-query](/hooks/use-media-query/) hook under the hood.
Hook relies on `window.matchMedia()` [API](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
and will always return false if api is not available (e.g. during server side rendering).
and will always return false if api is not available (e.g. during server side rendering), unless initial value is provided in the first argument.

Use hook to detect if user prefers to reduce motion (`(prefers-reduced-motion: reduce)` media query) and set animations duration based on this value.
All Mantine components which use animations support it by default:

<Demo data={HooksDemos.useReducedMotionDemo} />

## Definition

```tsx
function useReducedMotion(initialValue?: boolean): boolean;
```
4 changes: 2 additions & 2 deletions src/mantine-hooks/src/use-color-scheme/use-color-scheme.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMediaQuery } from '../use-media-query/use-media-query';

export function useColorScheme() {
return useMediaQuery('(prefers-color-scheme: dark)') ? 'dark' : 'light';
export function useColorScheme(initialValue?: 'dark' | 'light') {
return useMediaQuery('(prefers-color-scheme: dark)', initialValue === 'dark') ? 'dark' : 'light';
}
8 changes: 2 additions & 6 deletions src/mantine-hooks/src/use-media-query/use-media-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,21 @@ function getInitialValue(query: string, initialValue?: boolean) {
return window.matchMedia(query).matches;
}

// eslint-disable-next-line no-console
console.error(
'[@mantine/hooks] use-media-query: Please provide a default value when using server side rendering to prevent a hydration mismatch.'
);

return false;
}

export function useMediaQuery(query: string, initialValue?: boolean) {
const [matches, setMatches] = useState(getInitialValue(query, initialValue));
const queryRef = useRef<MediaQueryList>();

// eslint-disable-next-line consistent-return
useEffect(() => {
if ('matchMedia' in window) {
queryRef.current = window.matchMedia(query);
setMatches(queryRef.current.matches);
return attachMediaListener(queryRef.current, (event) => setMatches(event.matches));
}

return undefined;
}, [query]);

return matches;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMediaQuery } from '../use-media-query/use-media-query';

export function useReducedMotion() {
return useMediaQuery('(prefers-reduced-motion: reduce)');
export function useReducedMotion(initialValue?: boolean) {
return useMediaQuery('(prefers-reduced-motion: reduce)', initialValue);
}

0 comments on commit 61b8042

Please sign in to comment.