Skip to content

Commit

Permalink
refactor(useOrientationChange): rm useGlobalEventListener; make SSR r…
Browse files Browse the repository at this point in the history
…eady (#7811)

h2. Описание

- SSR: инициализируем как `'portrait'`, а в эффекте меняем значение на актуальное
- useGlobalEventListener: избавляемся, чтобы облегчить хук от лишних операций
- покрываем тестами
- реэкспоритурем тип `Orientation`

h2. Release notes
h2. Улучшения

- useOrientationChange:
  - поправлена проблема с гидрациией при SSR;
  - добавлен экспорт типа `Orientation`.
  • Loading branch information
inomdzhon authored Oct 23, 2024
1 parent 41c0684 commit 74715c7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 11 deletions.
33 changes: 33 additions & 0 deletions packages/vkui/src/hooks/useOrientationChange.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { renderHook } from '@testing-library/react';
import { useOrientationChange } from './useOrientationChange';

const mockScreenOrientation = (angle = 0, useDeprecated = false) => {
if (useDeprecated) {
Object.defineProperty(window, 'orientation', {
writable: true,
value: angle,
});
}

Object.defineProperty(window.screen, 'orientation', {
writable: true,
value: useDeprecated ? undefined : { angle },
});
};

describe(useOrientationChange, () => {
it.each([
{ angle: 0, type: 'portrait', useDeprecated: false },
{ angle: 90, type: 'landscape', useDeprecated: false },
{ angle: 0, type: 'portrait', useDeprecated: true },
{ angle: 90, type: 'landscape', useDeprecated: true },
])(
'returns $type if angle is $angle (useDeprecated="$useDeprecated")',
({ angle, type, useDeprecated }) => {
mockScreenOrientation(angle, useDeprecated);

const { result } = renderHook(useOrientationChange);
expect(result.current).toBe(type);
},
);
});
34 changes: 24 additions & 10 deletions packages/vkui/src/hooks/useOrientationChange.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import { useDOM } from '../lib/dom';
import { useGlobalEventListener } from './useGlobalEventListener';

type Orientation = 'portrait' | 'landscape';
export type Orientation = 'portrait' | 'landscape';

/**
* Возвращает текущую ориентация экрана на человеческом языке.
* Учитывает особенности API на разных платформах.
*/
function getOrientation(window: Window | undefined): Orientation {
if (!window) {
return 'portrait';
}

function getOrientation(window: Window): Orientation {
const angle = Math.abs(
// eslint-disable-next-line compat/compat
window.screen?.orientation?.angle ?? Number(window.orientation),
Expand All @@ -28,9 +23,28 @@ function getOrientation(window: Window | undefined): Orientation {
export function useOrientationChange(): Orientation {
const { window } = useDOM();

const [orientation, setOrientation] = React.useState(() => getOrientation(window));
const [orientation, setOrientation] = useState<Orientation>('portrait');

useEffect(
function mount() {
/* istanbul ignore if: невозможный кейс (в SSR вызова этой функции не будет) */
if (!window) {
return;
}

const handleChange = () => {
setOrientation(getOrientation(window));
};

useGlobalEventListener(window, 'orientationchange', () => setOrientation(getOrientation(window)));
handleChange();

window.addEventListener('orientationchange', handleChange);
return function unmount() {
window.removeEventListener('orientationchange', handleChange);
};
},
[window],
);

return orientation;
}
2 changes: 1 addition & 1 deletion packages/vkui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ export {
} from './hooks/useAdaptivityWithJSMediaQueries';
export { useColorScheme } from './hooks/useColorScheme';
export { usePagination } from './hooks/usePagination';
export { useOrientationChange } from './hooks/useOrientationChange';
export { type Orientation, useOrientationChange } from './hooks/useOrientationChange';
export { useTodayDate } from './hooks/useTodayDate';
export { useScrollLock } from './components/AppRoot/ScrollContext';
export { useNavTransition } from './components/NavTransitionContext/NavTransitionContext';
Expand Down

0 comments on commit 74715c7

Please sign in to comment.