Автор оригинала: Reed Barger.
Пользовательские реактивные крюки – это важный инструмент, который позволяет добавлять специальные, уникальные функциональные возможности в ваши приложения React.
Во многих случаях, если вы хотите добавить определенную функцию в ваше приложение, вы можете просто установить стороннюю библиотеку, которая сделана для решения вашей проблемы. Но если такая библиотека или крючка не существует, что вы делаете?
В качестве разработчика реагирования важно изучать процесс создания пользовательских крючков для решения проблем или добавления пропущенных функций в ваших собственных реагированных проектах.
В этом пошаговом руководстве я покажу вам, как создавать собственные пользовательские реактивные крюки, сломав три крючка, которые я сделал для моих собственных приложений, наряду с какими проблемами они были созданы для решения.
1. USECOPYTOCLIPBOARD Крюк
На прошлой версии моего сайта Reedbarger.com Я позволил пользователям копировать код из моих статей с помощью пакета под названием React-Copy-To-буфер обмена Отказ
Пользователь просто охватывает фрагмент, щелкнул кнопку буфера обмена, и код добавляется в буфер обмена их компьютера, чтобы включить их вставить и использовать код, где они понравится.
Однако вместо того, чтобы использовать третью сторону библиотеку, я хотел воссоздать эту функциональность с моим собственным пользовательским реагированным крюком. Как и при каждом пользовательском реактивный крюк, я создаю, я положил его выделенную папку, обычно называемую утилизация или lib В частности, для функций, которые я могу повторно использовать через мое приложение.
Мы поставим этот крюк в файл, называемый usecopytoclipboard.js, и я сделаю функцию того же имени.
Существуют различные способы копирования текста в буфер обмена пользователя. Я предпочитаю использовать библиотеку для этого, что делает процесс более надежным, называемым Копировать в буфер обмена Отказ
Он экспортирует функцию, которую мы позвоним Скопировать Отказ
// utils/useCopyToClipboard.js
import React from "react";
import copy from "copy-to-clipboard";
export default function useCopyToClipboard() {}
Далее мы создадим функцию, которая будет использоваться для копирования любых текста, которые хочет быть добавлены в буфер обмена пользователя. Мы назовем эту функцию Handlecopy Отказ
Как сделать функцию Handlecopy
Внутри функции нам сначала необходимо убедиться, что она принимает только данные, которые имеют тип строки или номера. Мы создадим Если-ж Заявление, которое удостоверится, что тип либо строка, либо число. Иначе мы будем регистрировать ошибку к консоли, которая сообщает пользователю, что вы не можете скопировать какие-либо другие типы.
import React from "react";
import copy from "copy-to-clipboard";
export default function useCopyToClipboard() {
const [isCopied, setCopied] = React.useState(false);
function handleCopy(text) {
if (typeof text === "string" || typeof text == "number") {
// copy
} else {
// don't copy
console.error(
`Cannot copy typeof ${typeof text} to clipboard, must be a string or number.`
);
}
}
}
Далее мы берем текст и преобразуем его в строку, которую мы будем перейти к Скопировать функция. Оттуда мы возвращаем Handlecopy Функция из крючка туда, где нам нравится в нашем приложении.
Вообще, Handlecopy Функция будет подключена к OnClick кнопки.
import React from "react";
import copy from "copy-to-clipboard";
export default function useCopyToClipboard() {
function handleCopy(text) {
if (typeof text === "string" || typeof text == "number") {
copy(text.toString());
} else {
console.error(
`Cannot copy typeof ${typeof text} to clipboard, must be a string or number.`
);
}
}
return handleCopy;
}
Кроме того, мы хотим некоторое состояние, которое представляет, был ли текст скопирован или нет. Чтобы создать это, мы позвоним Уместите В верхней части нашего крючка и сделайте новую переменную государства iscopied , где установка будет называться setcopy Отказ
Первоначально это значение будет ложным. Если текст успешно скопирован, мы установим Скопировать правда. Иначе мы установим его на ложь.
Наконец, мы вернемся iscopied от крючка в массиве вместе с Handlecopy Отказ
import React from "react";
import copy from "copy-to-clipboard";
export default function useCopyToClipboard(resetInterval = null) {
const [isCopied, setCopied] = React.useState(false);
function handleCopy(text) {
if (typeof text === "string" || typeof text == "number") {
copy(text.toString());
setCopied(true);
} else {
setCopied(false);
console.error(
`Cannot copy typeof ${typeof text} to clipboard, must be a string or number.`
);
}
}
return [isCopied, handleCopy];
}
Как использовать использование Копировать в буфер обмена
Теперь мы можем использовать UseCopyToclipboard в любом компоненте, который нам нравится.
В моем случае я буду использовать его с помощью компонента кнопки COPY, который получил код для нашего фрагмента кода.
Чтобы сделать эту работу, все, что нам нужно сделать, это добавить кнопку на кнопку. А в возвращении функции, называемой ручкой копия с кодом, заданным ему в качестве текста. И как только это скопировано, это правда. Мы можем показать другой значок, указывающий, что копия была успешной.
import React from "react";
import ClipboardIcon from "../svg/ClipboardIcon";
import SuccessIcon from "../svg/SuccessIcon";
import useCopyToClipboard from "../utils/useCopyToClipboard";
function CopyButton({ code }) {
const [isCopied, handleCopy] = useCopyToClipboard();
return (
);
}
Как добавить интервал сброса
Есть одно улучшение, которое мы можем сделать в наш код. Как мы в настоящее время написали наш крючок, iscopied Всегда будет правдой, то есть мы всегда будем видеть значок успеха:
Если мы хотим сбросить наше состояние через несколько секунд, вы можете пройти интервал времени на Используйте копию в буфер обмена Отказ Добавим эту функциональность.
Вернуться в наш крючок, мы можем создать параметр под названием ResetInterval , чье значение по умолчанию является null , что гарантирует, что государство не будет сброшено, если к нему не передано аргумент.
Затем мы добавим Useffect Сказать, что если текст скопирован, и у нас есть интервал сброса, мы установим iscopied Вернуться к false после этого интервала, используя Сетримс Отказ
Кроме того, нам нужно очистить этот тайм-аут, если наш компонент, который крюк используется в размонтировках (то есть наше состояние больше нет, чтобы обновить).
import React from "react";
import copy from "copy-to-clipboard";
export default function useCopyToClipboard(resetInterval = null) {
const [isCopied, setCopied] = React.useState(false);
const handleCopy = React.useCallback((text) => {
if (typeof text === "string" || typeof text == "number") {
copy(text.toString());
setCopied(true);
} else {
setCopied(false);
console.error(
`Cannot copy typeof ${typeof text} to clipboard, must be a string or number.`
);
}
}, []);
React.useEffect(() => {
let timeout;
if (isCopied && resetInterval) {
timeout = setTimeout(() => setCopied(false), resetInterval);
}
return () => {
clearTimeout(timeout);
};
}, [isCopied, resetInterval]);
return [isCopied, handleCopy];
}
Наконец, последнее улучшение мы можем сделать, это обернуть Handlecopy В UseCallback Крюк для того, чтобы гарантировать, что он не будет воссоздан каждый раз, когда есть рерандер.
Конечный результат
И с этим у нас есть последний крючок, который позволяет сбросить состояние после данного временного интервала. Если мы пройдем к нему, мы должны увидеть результат, как то, что у нас ниже.
import React from "react";
import ClipboardIcon from "../svg/ClipboardIcon";
import SuccessIcon from "../svg/SuccessIcon";
import useCopyToClipboard from "../utils/useCopyToClipboard";
function CopyButton({ code }) {
// isCopied is reset after 3 second timeout
const [isCopied, handleCopy] = useCopyToClipboard(3000);
return (
);
}
2. Usepagebottom крюк
В React Apps, иногда важно знать, когда ваш пользователь прокручивается до нижней части страницы.
В приложениях, где у вас есть бесконечный прокрутка, например, Instagram, например, после того, как пользователь попадает в нижнюю часть страницы, вам нужно получить больше сообщений.
Давайте посмотрим, как создать UsePageBottom, крюк себя за аналогичные случаи использования, такие как создание бесконечного прокрутки.
Начнем, сделав отдельный файл, usepagebottom.js, в нашей папке Utils, и мы добавим функцию (крючок) с тем же именем:
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {}
Далее нам нужно будет рассчитать, когда наш пользователь попадает в нижнюю часть страницы. Мы можем определить это с информацией из окно Отказ Чтобы получить доступ к этому, нам нужно будет убедиться, что наш компонент, который крюк вызывается внутри, установлен, поэтому мы будем использовать Useffect крючок с пустыми массивом зависимостей.
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {
React.useEffect(() => {}, []);
}
Пользователь будет прокручивать в нижнюю часть страницы, когда окно Innerheight Значение плюс документ Scrolltop Значение равно Offsetheight. . Если эти два значения равны, результат будет правдой, и пользователь прокручивается до нижней части страницы:
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {
React.useEffect(() => {
window.innerHeight + document.documentElement.scrollTop ===
document.documentElement.offsetHeight;
}, []);
}
Мы будем хранить результат этого выражения в переменной, Исботтом И мы обновим государственную переменную под названием снизу , который мы в конечном итоге вернусь с нашего крючка.
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {
const [bottom, setBottom] = React.useState(false);
React.useEffect(() => {
const isBottom =
window.innerHeight + document.documentElement.scrollTop ===
document.documentElement.offsetHeight;
setBottom(isButton);
}, []);
return bottom;
}
Наш код как есть, однако, не будет работать. Почему нет?
Вопрос заключается в том, что нам нужно рассчитать Исботтом Всякий раз, когда пользователь прокручивает. В результате нам нужно слушать событие прокрутки с window.addeventListener. . Мы можем переоценить это выражение, создав локальную функцию, которая будет называться всякий раз, когда пользовательские прокрутки, называемые Ручной помощью Отказ
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {
const [bottom, setBottom] = React.useState(false);
React.useEffect(() => {
function handleScroll() {
const isBottom =
window.innerHeight + document.documentElement.scrollTop
=== document.documentElement.offsetHeight;
setBottom(isButton);
}
window.addEventListener("scroll", handleScroll);
}, []);
return bottom;
}
Наконец, поскольку у нас есть прослушиватель событий, который является состоянием обновления, нам нужно обрабатывать событие, которое наш пользователь навигации от вдали от страницы, и наш компонент удален. Нам нужно удалить прослушиватель событий прокрутки, который мы добавили, поэтому мы не пытаемся обновить переменную состояния, которая больше не существует.
Мы можем сделать это, вернув функцию из Useffect вместе с window.reemoveeventListener , где мы передаем ссылку на то же самое Ручной помощью функция. И мы закончили.
// utils/usePageBottom.js
import React from "react";
export default function usePageBottom() {
const [bottom, setBottom] = React.useState(false);
React.useEffect(() => {
function handleScroll() {
const isBottom =
window.innerHeight + document.documentElement.scrollTop
=== document.documentElement.offsetHeight;
setBottom(isButton);
}
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return bottom;
}
Теперь мы можем просто вызвать этот код в любой функции, где мы хотим знать, нанес ли мы на дно страницы или нет.
В моем сайте GATSBY у меня есть заголовок, и, поскольку я уменьшаю размер страницы, я хочу показать меньше ссылок.
Для этого мы могли бы использовать медиа-запрос (CSS), или мы могли бы использовать пользовательский реактивный крюк, чтобы дать нам текущий размер страницы и скрыть или показывать ссылки в нашем JSX.
Раньше я использовал крючок из библиотеки под названием Воспользуйтесь реагированием Отказ Вместо того, чтобы принести целую стороннюю библиотеку, я решил создать свой собственный крючок, который обеспечил бы размеры окна, как ширину, так и высоту. Я позвонил этот крючок с помощью использованияWindowsize. .
Как создать крючок
Во-первых, мы создадим новый файл .js в папке наших утилит (utils), то же имя, что и крюк с помощью использованияWindowsize. . Я импортирую RECT (для использования крючков), экспортируя пользовательский крюк.
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {}
Теперь, поскольку я использую это на сайте GATSBY, который представляется сервером, мне нужно получить размер окна. Но у нас не может быть доступа к нему, потому что мы на сервере.
Чтобы проверить и убедиться, что мы не на сервере, мы можем увидеть, если тип окно не равно строке неопределенный .
В этом случае мы можем вернуться к ширине и высоте по умолчанию для браузера, скажем, 1200 и 800 в объекте:
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {
if (typeof window !== "undefined") {
return { width: 1200, height: 800 };
}
}
Как получить ширину и высоту от окна
И предполагая, что мы на клиенте и можем получить окно, мы можем взять Useffect Крюк для выполнения побочного эффекта, взаимодействуя с окно Отказ Мы включаем в себя пустой массив зависимостей, чтобы убедиться, что функция эффекта называется только после того, как компонент (чтобы этот крюк вызван) установлен.
Чтобы узнать ширину и высоту окна, мы можем добавить слушатель событий и слушать изменить размер мероприятие. И всякий раз, когда размеры браузера меняются, мы можем обновить часть состояния (созданный с steseState ), который мы позвоним windowsize и сеттер для обновления это будет SetWindowsize. .
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {
if (typeof window !== "undefined") {
return { width: 1200, height: 800 };
}
const [windowSize, setWindowSize] = React.useState();
React.useEffect(() => {
window.addEventListener("resize", () => {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
});
}, []);
}
Когда окно изменяется, обратный вызов будет вызван и windowsize Состояние будет обновлено с текущими размерами окна. Чтобы получить это, мы установили ширину на window.innerwidth и высота до window.innerheight Отказ
Как добавить поддержку SSR
Однако код, как у нас здесь, не будет работать. Это связано с тем, что ключевое правило крючков заключается в том, что их нельзя назвать условно. В результате мы не можем иметь условную выше наше Уместите или Useffect крючок, прежде чем они называются.
Итак, чтобы исправить это, мы установим начальное значение Уместите условно. Мы создадим переменную под названием ISSSR , что будет выполнять ту же проверку, чтобы увидеть, если окно не равно строке undefined Отказ
И мы будем использовать тройную, чтобы установить ширину и высоту, сначала проверяя, если мы на сервере. Если мы будем использовать значение по умолчанию, а если нет, мы будем использовать window.innerwidth и window.innerheight Отказ
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {
// if (typeof window !== "undefined") {
// return { width: 1200, height: 800 };
// }
const isSSR = typeof window !== "undefined";
const [windowSize, setWindowSize] = React.useState({
width: isSSR ? 1200 : window.innerWidth,
height: isSSR ? 800 : window.innerHeight,
});
React.useEffect(() => {
window.addEventListener("resize", () => {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
});
}, []);
}
Затем, наконец, нам нужно подумать, когда наши компоненты размонтируются. Что нам нужно сделать? Нам нужно удалить наше измерение слушателя.
Как удалить эффект события размера
Вы можете сделать это, возвращая функцию из AseFeffectand и. Мы удалим слушатель с window.reemoveeventListener Отказ
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {
// if (typeof window !== "undefined") {
// return { width: 1200, height: 800 };
// }
const isSSR = typeof window !== "undefined";
const [windowSize, setWindowSize] = React.useState({
width: isSSR ? 1200 : window.innerWidth,
height: isSSR ? 800 : window.innerHeight,
});
React.useEffect(() => {
window.addEventListener("resize", () => {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
});
return () => {
window.removeEventListener("resize", () => {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
});
};
}, []);
}
Но нам нужна ссылка на ту же функцию, а не два разных, как у нас здесь. Для этого мы создадим общий функцию обратного вызова для обоих слушателей, называемых изменить .
И, наконец, в конце крючка мы вернем нашу windowsize штат. Вот и все.
// utils/useWindowSize.js
import React from "react";
export default function useWindowSize() {
const isSSR = typeof window !== "undefined";
const [windowSize, setWindowSize] = React.useState({
width: isSSR ? 1200 : window.innerWidth,
height: isSSR ? 800 : window.innerHeight,
});
function changeWindowSize() {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
}
React.useEffect(() => {
window.addEventListener("resize", changeWindowSize);
return () => {
window.removeEventListener("resize", changeWindowSize);
};
}, []);
return windowSize;
}
Конечный результат
Чтобы использовать крючок, нам просто нужно импортировать его, где нам нужно, позвоните, и используйте ширину, где бы мы ни хотели скрыть или показать определенные элементы.
В моем случае это на марке 500 пикселей. Там я хочу скрыть все другие ссылки и только показать кнопку объединения сейчас, как вы видите в примере выше:
// components/StickyHeader.js
import React from "react";
import useWindowSize from "../utils/useWindowSize";
function StickyHeader() {
const { width } = useWindowSize();
return (
{/* visible only when window greater than 500px */}
{width > 500 && (
<>
Testimonials
Price
Question?
)}
{/* visible at any window size */}
Join Now
);
}
Этот крюк будет работать над любого сервера RACH APP, например GATSBY и Next.js.
3. UificevedeEtect Touch
Я в процессе создания новой посадочной страницы для моего курса, и я пережил очень странную ошибку на мобильных устройствах. На настольных компьютерах стили выглядели великолепно.
Но когда я посмотрел на мобильный телефон, все было вне места и сломалось.
Я отслеживал проблему до одной библиотеки под названием Реактивное устройство - обнаружение Что я использовал, чтобы обнаружить, имели ли пользователи мобильное устройство или нет. Если это так, я бы удалил заголовок.
// templates/course.js
import React from "react";
import { isMobile } from "react-device-detect";
function Course() {
return (
<>
{!isMobile && }
{/* more components... */}
);
}
Проблема заключалась в том, что эта библиотека не имеет поддержки для рендеринга на стороне сервера, который имеет использование GATSBY по умолчанию. Поэтому мне нужно было создать свое собственное решение для проверки, когда пользователь был на мобильном устройстве. И для этого я решил сделать пользовательский крючок с именем ИспользованЭтоэтектэтакт Отказ
Как я создал крючок
Я создал отдельный файл для этого крючка в моей папке UTILS с тем же именем, USEVECECETETECTECT.js. Поскольку крючки являются просто разделяемыми функциями JavaScript, которые используют реактивный крюки, я создал функцию под названием ИспользованЭтоэтектэтакт и импортируемый реагировать.
// utils/useDeviceDetect.js
import React from "react";
export default function useDeviceDetect() {}
Как получить пользовательский агент из окна
Способ того, что мы можем убедиться, что можем ли мы получить информацию о устройстве пользователя, проникает через свойство UserAgent (расположенное на недвижимости навигатора окна).
А с момента взаимодействия с API окна в качестве API/внешнего ресурса будет классифицироваться как побочный эффект, нам нужно получить доступ к пользователю агенту в Useffect крюк.
// utils/useDeviceDetect.js
import React from "react";
export default function useDeviceDetect() {
React.useEffect(() => {
console.log(`user's device is: ${window.navigator.userAgent}`);
// can also be written as 'navigator.userAgent'
}, []);
}
Как только компонент крепится, мы можем использовать Typeof Navigator Чтобы определить, есть ли мы на клиенте или сервере. Если мы на сервере, у нас не будет доступа к окну. Typeof Navigator будет равен строке неопределенный Так как это там нет. В противном случае, если мы на клиенте, мы сможем получить свой собственность агента пользователя.
Мы можем выразить все это, используя тройное, чтобы получить данные пользователя:
// utils/useDeviceDetect.js
import React from "react";
export default function useDeviceDetect() {
React.useEffect(() => {
const userAgent =
typeof navigator === "undefined" ? "" : navigator.userAgent;
}, []);
}
Как проверить, является ли useragent мобильное устройство
Useragent Это строковое значение, которое будет установлено на любое из следующих имен устройств, если они используют мобильное устройство:
Android, BlackBerry, iPhone, iPad, iPod, Opera Mini, iemobile или wpdesktop.
Все, что нам нужно сделать, это сделать строку, которую мы получаем и используем .match () Способ с регулярным выражением, чтобы увидеть, кажется ли это одной из этих строк. Мы будем хранить его в локальной переменной под названием Мобильный Отказ
Мы будем хранить результат в штате с помощью Usestate Hook, который мы дадим первоначальное значение false. Для него мы создадим соответствующую переменную государство Ismobile и сеттер будет SetMobile Отказ
// utils/useDeviceDetect.js
import React from "react";
export default function useDeviceDetect() {
const [isMobile, setMobile] = React.useState(false);
React.useEffect(() => {
const userAgent =
typeof window.navigator === "undefined" ? "" : navigator.userAgent;
const mobile = Boolean(
userAgent.match(
/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i
)
);
setMobile(mobile);
}, []);
}
Так как только мы получим Мобильный Значение мы установим его в состоянии. Затем, наконец, мы вернем объект с крючка, чтобы мы могли добавить больше значений в будущем, если мы хотим выбрать дополнительную функциональность к этому крюку.
В объекте мы добавим Ismobile как свойство и значение:
// utils/useDeviceDetect.js
import React from "react";
export default function useDeviceDetect() {
const [isMobile, setMobile] = React.useState(false);
React.useEffect(() => {
const userAgent =
typeof window.navigator === "undefined" ? "" : navigator.userAgent;
const mobile = Boolean(
userAgent.match(
/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i
)
);
setMobile(mobile);
}, []);
return { isMobile };
}
Конечный результат
Назад на целевой странице мы можем выполнить крючок и просто получить эту недвижимость от разрушенного объекта и использовать его, где нам это нужно.
// templates/course.js
import React from "react";
import useDeviceDetect from "../utils/useDeviceDetect";
function Course() {
const { isMobile } = useDeviceDetect();
return (
<>
{!isMobile && }
{/* more components... */}
);
}
Заключение
Как я пытался проиллюстрировать через каждый из этих примеров, пользовательские реактивный крючки могут дать нам инструменты для устранения собственных проблем, когда сторонние библиотеки не хватают.
Я надеюсь, что это руководство дало вам лучшее представление о том, когда и как создавать свои собственные реактивные крюки. Не стесняйтесь использовать любой из этих крючков и вышеупомянутых в своих собственных проектах и в качестве вдохновения для собственных пользовательских реактивных крючек.
Наслаждайтесь этим постом? Присоединяйтесь к React BootCamp
React Bootcamp Занимает все, что вы должны знать о изучении реагирования и связки в один комплексный пакет, включая видео, обманывать, плюс специальные бонусы.
Получить инсайдерскую информацию сотни разработчиков уже использовалось для освоения реагирования, находить работу своей мечты и контролировать свое будущее:
Нажмите здесь, чтобы быть уведомленным, когда он открывается
Оригинал: “https://www.freecodecamp.org/news/how-to-create-react-hooks/”