@ws-serenity/react-hooks
v3.4.5
Published
Some common hooks for React application
Downloads
168
Keywords
Readme
Базовые хуки
useDebounce
Функция откладывает вызов колбэка на указанное время
const [ searchText, setSearchText ] = useState('');
const [ displayedParticipants, setDisplayedParticipants ] = useState(userParticipants);
// будет вызвана, когда ввод прекратится на SEARCH_INPUT_DEBOUNCE_DELAY милисекунд
const onSetDisplayedParticipants = (searchText: string) => {
setDisplayedParticipants(userParticipants.filter(user => user.person.displayName.includeIgnoringCase(searchText)));
};
const debounceFilter = useDebounce<string>(onSetDisplayedParticipants, SEARCH_INPUT_DEBOUNCE_DELAY);
useEffect(() => debounceFilter(searchText), [ searchText ]);
useOutsideClick
Колбэк вызывается, когда происходит нажатие за пределами ref указанного компонента
const [ isMenuOpen, setIsMenuOpen ] = useState(false);
const menuRef = useOutsideClick<HTMLDivElement>(() => setIsMenuOpened(false));
useResizeObserver
Следит за изменением размера любого HTML-элемента, при изменении вызывает колбэк. Возвращает ref, за обновлением элемента которого будет следить.
const updateSizeCount = useCallback(() => {
// обновление стейта работает, но для этого неоходим дополнительный объект с постоянной ссылкой, чтобы замыкание сработало на него
sizeChangedCountRef.current = sizeChangedCountRef.current + 1;
setSizeChangedCount(sizeChangedCountRef.current);
}, []);
// так делать НЕ НАДО
const WRONG_updateSizeCount = useCallback(() => {
// в противном случае значение стейта - значимого типа (sizeChangedCount) - всегда будет оставаться прежним, потому что замкнется
setSizeChangedCount(sizeChangedCount + 1);
}, []);
const containerRef = useResizeObserver<HTMLUListElement>(updateSizeCount);
useTouchHold
Предназначен для вызова колбэка при удержании элемента на мобильном и планшетном устройстве
function SomeComponent() {
const ref = useTouchHold<HTMLDivElement>(onOpenParticipantsModal, OPEN_PARTICIPANTS_MODAL_DELAY);
return (
<div
className={'perticipant'}
ref={ref}
>
</div>
)
}
useKeyPress
Позволяет добавлять хэндлеры для нажатия определенных клавиш.
useKeyPress({
keyPressParams: {
Escape: {
onKeyDown: () => setMessage('There\'s no escape from simulation'),
},
ArrowUp: {
onKeyDown: () => {},
},
ArrowLeft: {
onKeyDown: () => {},
},
ArrowDown: {
onKeyDown: () => {},
},
ArrowRight: {
onKeyDown: () => {},
},
},
options: { passive: true },
});
| Параметр | Тип | По умолчанию | Описание |
|----------------|--------------------------|---------------------|----------------------------------------------------|
| keyPressParams | UseKeyPressParams
| | Объект, описывающий обработчики для каждого ключа. |
| target | RefObject<HTMLElement>
| | Элемент, на котором необходимо отловить событие. |
| options | AddEventListenerOptions
| { capture: true }
| Опции стандартного EventListner'а. |
useFileSelect
Вызывает API браузера для выбора файла.
import { useFileSelect } from '@ws-serenity/react-hooks';
const selectFile = useFileSelect({
handleSelect: () => { /* ... */ },
multiple: true,
accept: {
extensions: [ 'ftl', 'gtl' ],
},
});
selectFile();
| Параметр | Тип | По умолчанию | Описание |
|--------------|---------------------------|--------------|-------------------------------------------------------------------------|
| handleSelect | (files: File[]) => void
| | Обработчик для выбранных файлов. |
| multiple | boolean
| false
| Разрешить выбирать несколько файлов. |
| accept | AcceptConfig
| | Задает параметры для фильтрации файлов по их расширению и их mime type. |
export type AcceptConfig = {
// Регистр не учитывается
// Должны быть заданы без точки
// [ '.pdf', '.txt' ] - ⚠️ неправильно
// [ 'pdf', 'PDF', 'txt', 'TXT' ] - ⚠️ допустимо
// [ 'pdf', 'txt' ] - ✅ правильно
extensions?: string[],
// Регистр не учитывается
// Будет расширено до обобщения images -> images/*
// [ 'image/jpeg', 'image/png' ... ] - ⚠️ неправильно
// [ 'IMAGE', 'VIDEO' ] - ⚠️ допустимо, но с нарушением name convention
// [ 'image', 'video' ] - ✅ правильно
mimeTypes?: string[],
}
useDropZone
Отслеживает перетаскивание файлов в контейнер.
Также, может обработать клик на контейнер, вызвав browser api для выбора файла.
Возвращает флаг isActive
, коллекцию listeners
и метод selectFiles
.
import { useDropZone } from '@ws-serenity/react-hooks';
const {
isActive,
listeners,
selectFiles
} = useDropZone();
/* ... */
<div
className={isActive ? 'drop-zone drop-zone--active' : 'drop-zone'}
{...listeners}
>
{/* ... */}
</div>
<button onClick={selectFiles}>Add files</button>
| Возврат | Тип | Описание |
|-----------------|--------------|--------------------------------------------------------------------------------------|
| isActive | boolean
| true
если перетаскиваемый объект находится в зоне контейнера, false
иначе. |
| isWindowsActive | boolean
| true
, если перетаскиваемый объект находится в зоне окна, false
иначе. |
| listeners | Listeners
| Коллекция listeners на которые нужно подписать контейнер для корректной работы хука. |
| selectFiles | () => void
| Вызывает browser api для выбора файла, игнорирует dropOnly
флаг. |
| Параметр | Тип | По умолчанию | Описание |
|------------|---------------------------|--------------|--------------------------------------------------------------------------------------------------------------|
| handleDrop | (files: File[]) => void
| | Обработчик для выбранных файлов. |
| dropOnly | boolean
| false
| Если true
, то файлы буду добавляться только перетаскиванием. |
| filterDrop | boolean
| true
| Если false
, то файлы, добавленные перетаскиванием, не будут проверяться на соответствие условиям accept
. |
| disabled | boolean
| false
| Если true
, то работа хука приостанавливается. |
| multiple | boolean
| true
| Разрешить выбирать несколько файлов. |
| accept | AcceptConfig
| | Задает параметры для фильтрации файлов по их расширению и их mime type. |
AcceptConfig - см. useFileSelect.AcceptConfig.
useCallbackRef
Хук, объединяющий cb = useCallback( /* ... */ )
и cbRef = useRef(cb)
.
import { useCallback } from "react";
import { useCallbackRef } from "@ws-serenity/react-hooks";
const callback = useCallback(() => { /* ... */ }, []);
const [ cb, cbRef ] = useCallbackRef(() => { /* ... */ }, []);
Мотивация - невозможность обновить анонимную функцию, использующую коллбэк, например:
import { useCallback } from "react";
type AirType = 'normal' | 'discharged';
const air: AirType = 'normal';
const breathe = useCallback(() => { /* ... */ }, [ air ]);
const human = {
/* ... */
breathe: async () => breathe()
}
В примере выше, метод human.breathe()
не обновится вместе с breathe
.
Чтобы это исправить, можно использовать ссылку на коллбэк.
const [ breathe, breatheRef ] = useCallbackRef(() => { /* ... */}, [ air ]);
const human = { /* ... */ breathe: async () => breatheRef.current() }
Также, этот хук позволяет использовать некоторые оптимизации мемоизации, позволяя не подписываться на изменение коллбэка.
useClipboard
Обработчик для различных событий буфера обмена
import { useClipboard } from '@ws-serenity/react-hooks';
useClipboard({
onPasteFiles: (files: File[]) => console.log(files),
});
initEsiaAuth
Функция для упрощения авторизации через ESIA, является инициализирующей функцией и ее ЗАПРЕЩАЕТСЯ использовать внутри компонента, потому что функция возвращает 2 хука - один для начала авторизации, второй для ее завершения.
Авторизацию можно легко доработать до "любой сторонней авторизации", например, до GoogleAuth, но пока не требуется
// инициализация хуков в отдельном модуле
import { initEsiaAuth } from '@ws-serenity/react-hooks';
const [
useAuthEsiaInit,
useAuthEsiaComplete,
] = initEsiaAuth(
`${apiUrl}/auth-service/esia/init?redirectUrl=https://${window.location.hostname}/auth/external/esia`,
);
export { useAuthEsiaInit, useAuthEsiaComplete };
// компонент вызова esia, с которым взаимодействует пользователь
export function AuthEsiaButton() {
// передаем метод авторизации, который необходимо вызвать, мы не можем перенести функцию в init,
// чтобы обеспечить совместимость с другими хуками, а не только с глобальными функциями
const start = useAuthEsiaInit((dto) => signIn('auth-esia', { ...dto, redirect: false }));
return (
<button onClick={start}>Войти через ESIA</button>
);
}
// отдельная страница, на которую мы получим редирект после успешной авторизации
// auth/[code]/esia
export default function EsiaAuthPage({ code }: EsiaAuthPageProps) {
// сюда можно передать необходимые данные любым способом
useAuthEsiaComplete(code, [code]);
return (<AppLoader/>);
}
useIosFriendlyClick
По какой-то причине просто onclick не срабатывает в некоторых случаях в Web на iOS
С такой проблемой столкнулись в списке опций селекта на ios. Баг воспроизводился во всех браузерах iOS
Советы из интернетов не помогли (https://stackoverflow.com/questions/24077725/mobile-safari-sometimes-does-not-trigger-the-click-event) поэтому было состряпано собственное решение
При использовании хука нет необходимости вручную навешивать onClick