7 React Hooks для каждого проекта
Hooks - одна из самых мощных функций React.
Они позволяют нам легко повторно использовать функциональность всех компонентов нашего приложения. Что лучше всего в крючках, так это их возможность повторного использования – вы можете повторно использовать свои крючки как в компонентах, так и в ваших проектах.
Вот семь наиболее важных хуков, которые повторно используются в каждом проекте React, который мы создаем. Попробуйте их сегодня и посмотрите, будут ли они так же полезны для вас при создании собственных приложений React.
Прежде чем мы начнем, важно уточнить, что не каждый пользовательский хук React должен быть написан вами. На самом деле, все крючки, о которые будут упомянуты, взяты из библиотеки @mantine/hooks
.
Mantine - отличная сторонняя библиотека, которая включает в себя эти хуки и многое другое. Они добавят в ваше приложение React практически все важные функции, о которых вы только можете подумать.
Вы можете ознакомиться с документацией для @mantine/hooks
на mantine.dev..
Hook useIntersection
Когда пользователь прокручивает страницу вниз в вашем приложении, вы можете захотеть узнать, когда элемент виден для него.
Например, вы можете захотеть запустить анимацию только тогда, когда пользователь увидит определенный элемент. Или же вы можете захотеть показать или скрыть элемент после того, как они прокрутили определенную часть страницы вниз.
Чтобы получить информацию о том, виден ли элемент, мы можем использовать Intersection Observer API. Это JavaScript API, встроенный в браузер.
Мы можем использовать API сам по себе, используя обычный JavaScript, но отличный способ получить информацию о том, пересекается ли конкретный элемент в его контейнере прокрутки, - это использовать hook useIntersection
.
import { useRef } from 'react';
import { useIntersection } from '@mantine/hooks';
function Demo() {
const containerRef = useRef();
const { ref, entry } = useIntersection({
root: containerRef.current,
threshold: 1,
});
return (
<main ref={containerRef} style={{ overflowY: 'scroll', height: 300 }}>
<div ref={ref}>
<span>
{entry?.isIntersecting ? 'Fully visible' : 'Obscured'}
</span>
</div>
</main>
);
}
Чтобы использовать его, все, что нам нужно сделать, это вызвать хук в нашем компоненте и предоставить корневой элемент. Root - это контейнер прокрутки, и он может быть предоставлен как ссылка с помощью крючка useRef.
useIntersection
возвращает ссылку, которую мы передаем целевому элементу, пересечение которого в контейнере прокрутки мы хотим наблюдать.
Как только у нас есть ссылка на элемент, мы можем отслеживать, пересекается ли элемент или нет. В приведенном выше примере мы можем видеть, когда элемент скрыт или когда он полностью виден, основываясь на значении entry.isIntersecting
.
Вы можете передать дополнительные аргументы, которые позволят вам настроить пороговое значение, связанное с тем, какой процент целевого объекта виден.
Hook useScrollLock
Еще одним крючком, связанным с прокруткой, является крючок useScrollLock
. Этот хук очень прост: он позволяет вам заблокировать любую прокрутку на элементе body.
Мы обнаружили, что это полезно всякий раз, когда вы хотите отобразить наложение или модальный элемент поверх текущей страницы и не хотите разрешать пользователю прокручивать страницу вверх и вниз в фоновом режиме. Это позволяет вам либо сосредоточить внимание на модальном элементе, либо разрешить прокрутку в его собственном контейнере прокрутки.
import { useScrollLock } from '@mantine/hooks';
import { Button, Group } from '@mantine/core';
import { IconLock, IconLockOpen } from '@tabler/icons';
function Demo() {
const [scrollLocked, setScrollLocked] = useScrollLock();
return (
<Group position="center">
<Button
onClick={() => setScrollLocked((c) => !c)}
variant="outline"
leftIcon={scrollLocked ? <IconLock size={16} /> : <IconLockOpen size={16} />}
>
{scrollLocked ? 'Unlock scroll' : 'Lock scroll'}
</Button>
</Group>
);
}
useScrollLock
блокирует прокрутку пользователя в его текущем положении на странице. Функция возвращает массив, который может быть структурирован, как в приведенном выше коде.
Второе значение - это функция, которая позволяет нам блокировать прокрутку. С другой стороны, первое разрушенное значение - это логическое значение, которое сообщает нам, была ли прокрутка заблокирована или нет.
Это значение полезно, например, если вы хотите показать определенный контент, когда прокрутка заблокирована, или сообщить пользователю, что он заблокирован. Вы можете видеть в примере ниже, что мы указываем внутри нашей кнопки, когда прокрутка была заблокирована или разблокирована.
Hook useClipboard
Во многих случаях вы хотите предоставить кнопку, которая позволяет пользователю копировать что-либо в свой буфер обмена, где хранится скопированный текст.
Отличный пример этого - если у вас есть фрагмент кода на вашем веб-сайте, и вы хотите, чтобы пользователи могли легко скопировать его. Для этого мы можем использовать другой веб–API - Clipboard API.
@mantine /hooks
предоставляет нам удобный хук useClipboard
, который возвращает пару свойств: copied
, представляющий собой логическое значение, которое сообщает нам, было ли значение скопировано в буфер обмена с помощью хука, а также функцию copy
, которой мы можем передать любое строковое значение, которое нам нравится, чтобы оно было скопировано.
В нашем примере мы хотели бы скопировать фрагмент кода, чтобы наши пользователи могли вставить его туда, куда им нравится, как показано на видео ниже:
useClipboard demo
Мы вызываем нашу функцию copy
, когда они нажимают указанную нами кнопку копирования, передаем ей фрагмент кода, а затем показываем небольшую галочку или что-то еще, указывающее им, что текст был скопирован.
Что примечательно, так это то, что крючок useClipboard
поставляется со значением тайм-аута. По истечении заданного периода ожидания, который составляет миллисекунды, скопированное состояние будет сброшено, показывая пользователю, что он может скопировать текст снова.
Hook useDebouncedValue
Следующий хук, useDebouncedValue
, необходим, если у вас есть поисковый ввод в вашем приложении.
Всякий раз, когда пользователь выполняет поиск с использованием входных данных, операция поиска обычно включает HTTP-запрос к API.
Типичная проблема, с которой вы столкнетесь, особенно если вы хотите, чтобы ваши пользователи получали результаты поиска по мере ввода текста, заключается в том, что запрос (request) будет выполняться при каждом нажатии клавиши. Даже для простого поискового запроса нет необходимости выполнять так много запросов, прежде чем пользователь закончит вводить то, что он хочет.
Это отличный вариант использования крючка useDebounceValue
, который применяет функцию debounce к тексту, который был передан ему.
import { useState } from 'react';
import { useDebouncedValue } from '@mantine/hooks';
import { getResults } from 'api';
function Demo() {
const [value, setValue] = useState('');
const [results, setResults] = useState([])
const [debounced] = useDebouncedValue(value, 200); // wait time of 200 ms
useEffect(() => {
if (debounced) {
handleGetResults()
}
async function handleGetResults() {
const results = await getResults(debounced)
setResults(results)
}
}, [debounced])
return (
<>
<input
label="Enter search query"
value={value}
style={{ flex: 1 }}
onChange={(event) => setValue(event.currentTarget.value)}
/>
<ul>{results.map(result => <li>{result}</li>}</ul>
</>
);
}
Вы сохраняете текст из вашего ввода в фрагменте состояния с помощью useState
и передаете переменную состояния в useDebouncedValue
.
В качестве второго аргумента для этого крючка вы можете указать время ожидания, которое представляет собой период времени, в течение которого значение сбрасывается. Дебаунс - это то, что позволяет нам выполнять гораздо меньше запросов.
Вы можете увидеть результат в видео ниже, где пользователь вводит что-то, и только через 200 миллисекунд мы видим отмененное значение.
Hook useMediaQuery
Еще один очень полезный хук, который используется постоянно, - это хук useMediaQuery
.
Медиа-запросы используются в обычном CSS, а хук useMediaQuery
позволяет нам подписаться на любой медиа-запрос, который мы передаем в хук.
Например, в нашем компоненте, допустим, мы хотим отобразить некоторый текст или изменить стили компонента в зависимости от определенной ширины экрана, например 900 пикселей. Мы предоставляем медиа-запрос точно так же, как в CSS, и useMediaQuery
возвращает нам значение matches
, которое либо истинно, либо ложно.
import { useMediaQuery } from '@mantine/hooks';
function Demo() {
const matches = useMediaQuery('(min-width: 900px)');
return (
<div style={{ color: matches ? 'teal' : 'red' }}>
{matches ? 'I am teal' : 'I am red'}
</div>
);
}
Он сообщает нам результат этого медиа-запроса в JavaScript, что особенно полезно, когда у нас есть стили, которые мы хотим изменить непосредственно в нашем JSX, например, используя style
prop.
Короче говоря, это важный крючок для тех немногих случаев, когда CSS нельзя использовать для обработки медиа-запросов.
Hook useClickOutside
Этот следующий хук – useClickOutside
– может показаться странным, но вы увидите, насколько он важен, когда он вам действительно понадобится.
Когда вы разрабатываете выпадающий список или что-то еще, что появляется перед содержимым страницы и после этого должно быть закрыто (например, модальное окно или ящик), этот крючок незаменим. Очень легко открыть один из этих типов компонентов, нажав на кнопку. Закрыть эти компоненты немного сложнее.
Чтобы следовать хорошей практике UX, мы хотим, чтобы все, что мешает обзору нашего пользователя, было легко закрыто щелчком за пределами элемента. Это именно то, что позволяет нам делать крючок useClickOutside
.
Когда мы вызываем useClickOutside
, он возвращает ссылку, которую мы должны передать элементу, за пределами которого мы хотим обнаруживать клики. Обычно этим элементом будет управлять логический элемент состояния, подобный тому, который мы имеем в нашем примере ниже (то есть значение opened
).
import { useState } from 'react';
import { useClickOutside } from '@mantine/hooks';
function Demo() {
const [opened, setOpened] = useState(false);
const ref = useClickOutside(() => setOpened(false));
return (
<>
<button onClick={() => setOpened(true)}>Open dropdown</button>
{opened && (
<div ref={ref} shadow="sm">
<span>Click outside to close</span>
</div>
)}
</>
);
}
useClickOutside
принимает функцию обратного вызова, которая управляет тем, что происходит, когда вы на самом деле щелкаете за пределами этого элемента.
В большинстве случаев мы хотим сделать что-то довольно простое, а именно просто закрыть его. Для этого вам, вероятно, потребуется установить параметр состояния (например, setOpened
) и передать ему значение false, чтобы затем скрыть наложенный контент.
Hook useForm
Наш любимый и самый полезный хук в этом списке — хук useForm
.
Этот хук поставляется специально из Mantine и включает в себя установку определенного пакета из библиотеки: @mantine/form
. Это должно предоставить вам все, что вам нужно для создания форм в React, включая возможность проверки входных данных, отображения сообщений об ошибках и проверки правильности входных значений перед отправкой формы.
useForm
принимает некоторые начальные значения, которые соответствуют любым входным данным, которые вы имеете в своей форме.
import { TextInput, Button } from '@mantine/core';
import { useForm } from '@mantine/form';
function Demo() {
const form = useForm({
initialValues: {
email: ''
},
validate: {
email: (value) => (/^\S+@\S+$/.test(value) ? null : 'Invalid email'),
},
});
return (
<div>
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
withAsterisk
label="Email"
placeholder="your@email.com"
{...form.getInputProps('email')}
/>
<Button type="submit">Submit</Button>
</form>
</div>
);
}
Большим преимуществом useForm
являются его помощники, такие как функция validate
, которая получает значение, которое было введено для каждого ввода, а затем позволяет вам создавать правила проверки.
Например, если у вас есть ввод электронной почты, у вас может быть регулярное выражение, чтобы определить, действительно ли это действительный адрес электронной почты (как вы можете видеть в приведенном выше коде). Если нет, вы можете отобразить сообщение об ошибке и предотвратить отправку формы.
Как вы получаете значения, которые были введены в форму?
Mantine предоставляет очень удобный помощник под названием getInputProps
, где вы просто указываете имя ввода, с которым вы работаете (например, электронная почта), и он автоматически настраивает onChange для отслеживания значений, которые вы ввели в свою форму.
Кроме того, для обработки отправки формы и предотвращения отправки, если ее значения не проходят правила проверки, у него есть специальная функция onSubmit
, которую вы оборачиваете на обычную функцию onSubmit
. Помимо применения правил проверки, он позаботится о вызове preventDefault()
для события формы, чтобы вам не приходилось делать это вручную.
Мы только царапаем поверхность этим крючком, но настоятельно рекомендуем вам использовать его для вашего следующего проекта. Формы традиционно вызывают затруднения при правильной работе, особенно формы, которые требуют проверки и видимых сообщений об ошибках. useForm
делает это невероятно простым!
Как мы видели в этом посте, существует множество мощных хуков, которые мы можем использовать для создания наших приложений.