DEV Community

Mukhammad Sobirov
Mukhammad Sobirov

Posted on

12

Кастомный 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.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

SurveyJS custom survey software

Build Your Own Forms without Manual Coding

SurveyJS UI libraries let you build a JSON-based form management system that integrates with any backend, giving you full control over your data with no user limits. Includes support for custom question types, skip logic, an integrated CSS editor, PDF export, real-time analytics, and more.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay