DEV Community

Muhammed Sobirov
Muhammed Sobirov

Posted on

Кастомный React хук— useDebounce

Одна из замечательных особенностей React заключается в том, что он позволяет создавать собственные хуки и предлагать более эффективные способы решения проблем. Понимание того, как создать собственный хук, является ценным навыком разработчика. Есть много отличных кастомных хуков, которые «стандартизированы» в сообществе разработчиков React, и useDebounce() — один из них.

В этой статье мы собираемся создать мини-приложение, которое позволит пользователям искать изображения из Unsplash API. Я также предоставлю ссылку на репозиторий Github.

Создание акаунта в Unsplash

  1. Сначала нам нужно зарегистрироваться в Unsplash
  2. Далее нам нужно создать там новое приложение

создание акканта в unsplash

важно отметить, что мы будем использовать их демонстрационное приложение, которое имеет ограничение в 50 запросов в час. Для готовых к производству приложений проверьте их требования на той же странице. Также ознакомьтесь с их рекомендациями по использованию API.

  1. Наконец, обязательно скопируйте ключ доступа и секретные ключи, которые они предоставляют.

Создание приложения

Просто создайте минимальное React приложение. Я использую Vite.

npm create vite@latest 
Enter fullscreen mode Exit fullscreen mode

Выберите простой шаблон React на основе JavaScript и позвольте ему настроить проект. После завершения настройки нажмите npm i.

Когда все будет готово, создайте файл .env в корневой папке проекта.

создание env файла

И добавьте ключи доступа и секретные ключи, как показано ниже. Если вы используете Vite, важно начинать имя ключа с «VITE».

VITE_ACCESS_KEY="your key" VITE_SECRET_KEY="your key" 
Enter fullscreen mode Exit fullscreen mode

Затем перейдите к файлу App.jsx и удалите оттуда лишний код, как показано ниже:

import { useState } from "react"; import "./App.css"; function App() { return <div className="App"></div>; } export default App; 
Enter fullscreen mode Exit fullscreen mode

Мы собираемся добавить сюда простой компонент search, чтобы пользователь мог ввести слово для поиска.

import { useState } from "react"; import "./App.css"; function App() { const [searchTerm, setSearchTerm] = useState(""); return ( <div className="App"> <div> <label htmlFor="search-input">Search Unsplash images</label> <input type="search" id="search-input" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> </div> </div> ); } export default App; 
Enter fullscreen mode Exit fullscreen mode

Идея в том, что мы отправляем запрос в Unsplash API каждый раз, когда пользователь обновляет слово поиска. Простым способом реализации этой логики было бы использование useEffect с searchTerm в массиве зависимостей.

import { useState, useEffect } from "react"; import "./App.css"; function App() { const [searchTerm, setSearchTerm] = useState(""); const handleSearch = () => { console.log("searching for", searchTerm); }; useEffect(() => { handleSearch(); }, [searchTerm]); return ( <div className="App"> <div> <label htmlFor="search-input">Search Unsplash images</label> <input type="search" id="search-input" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> </div> </div> ); } export default App; 
Enter fullscreen mode Exit fullscreen mode

Можете ли вы угадать проблему с этим подходом? Откроем консоль браузера и проверим, что там происходит:

Image description

Помните, что у нас есть ограничение в 50 запросов в час. Даже если бы у нас было больше, отправка запроса в API при каждом вводе пользователем — не очень масштабируемая и дорогая операция. В идеале вы хотели бы дождаться, пока пользователь введет слово целиком, а затем отправить запрос. Вот где в игру вступает useDebounce! так что давайте реализуем это дальше.

useDebounce()

Давайте создадим файл с именем useDebounce:

useDebounce хук

Внутри файла мы собираемся написать сам хук. Идея в том, что мы хотим предотвратить быстрое изменение состояния searchTerm . Этот хук принимает два входных параметра — значение, которое должно “отскочить”, и задержка в миллисекундах (обычно 500). При объединении useDebounce с useEffect вы можете быть уверены, что будет отражено только самое последнее значение, поскольку хук не будет вызываться в течение указанного времени. Вот код:

function useDebounce(value, delay) { // value and delay in ms (1000ms = 1s) // debounced values const [debouncedValue, setDebouncedValue] = useState(value); useEffect( () => { // Update debounced value after delay const t = setTimeout(() => { setDebouncedValue(value); }, delay); // clean up the timeout after value changes return () => { clearTimeout(t); }; }, [value, delay] // re-run if value or delay changes ); return debouncedValue; } export default useDebounce; 
Enter fullscreen mode Exit fullscreen mode

Наконец, давайте объединим это с нашей существующей логикой и сравним с предыдущим поведением:

import { useState, useEffect } from "react"; import "./App.css"; import useDebounce from "./useDebounce"; function App() { const [searchTerm, setSearchTerm] = useState(""); const debouncedSearchTerm = useDebounce(searchTerm, 500); const handleSearch = () => { console.log("searching for", searchTerm); }; useEffect(() => { if (debouncedSearchTerm) { handleSearch(); } }, [debouncedSearchTerm]); return ( <div className="App"> <div> <label htmlFor="search-input">Search Unsplash images</label> <input type="search" id="search-input" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> </div> </div> ); } export default App; 
Enter fullscreen mode Exit fullscreen mode

Разве это не безумие, насколько эффективной стала наша поисковая логика?

демонстрация

Unsplash интеграция

Теперь с этим кодом мы можем безопасно интегрировать поиск Unsplash.

import { useState, useEffect } from "react"; import "./App.css"; import useDebounce from "./useDebounce"; const API_URL = "https://api.unsplash.com/search/photos"; function App() { const [searchTerm, setSearchTerm] = useState(""); const [results, setResults] = useState([]); const debouncedSearchTerm = useDebounce(searchTerm, 500); const handleSearch = async () => { const response = await fetch( `${API_URL}?query=${debouncedSearchTerm}&client_id=${import.meta.env.VITE_ACCESS_KEY}` ); const data = await response.json(); return data.results; }; useEffect(() => { if (debouncedSearchTerm) { handleSearch().then((results) => setResults(results)); } }, [debouncedSearchTerm]); return ( <div className="App"> <div> <label htmlFor="search-input">Search Unsplash images</label> <input type="search" id="search-input" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> </div> <div> {results?.map((result) => ( <img key={result.id} src={result.urls.small} alt={result.alt_description} /> ))} </div> </div> ); } export default App; 
Enter fullscreen mode Exit fullscreen mode

финальное приложение

Вот и все

Я надеюсь, что вы нашли эту статью/туториал полезным. Я рекомендую вам попробовать useDebounce в своих проектах и создавать высококачественные приложения. Вот ссылка на репозиторий Github.

Top comments (0)