Создание пользовательских хуков React: полное руководство

Хуки  —  это функции React, которые позволяют добавлять состояние и другие функции в функциональные компоненты. До появления хуков состояние и другие функции React можно было использовать только в компонентах классов.

Введение хуков позволило разработчикам писать более компактный и понятный код.

React-хуки были введены в React 16.8 и стали популярной фичей в React-сообществе. Многие разработчики сразу оценили способность хуков обеспечивать более гибкий и удобный в обслуживании код. Новичкам рекомендуется освоить встроенные хуки и разобраться с тем, как создавать пользовательские хуки, поскольку это значительно упрощает React-разработку.

В React есть несколько встроенных хуков, таких как useState и useEffect, которые можно использовать для добавления состояния и обработки побочных эффектов в функциональных компонентах. Однако настоящая сила этой фичи заключается в возможности создания пользовательских хуков.

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

Вот что делает React-хуки ценным инструментом для веб-приложений.

  • Возможность повторного использования. Хуки позволяют извлекать и повторно использовать состояние и другую логику в нескольких компонентах. Это делает код более организованным и удобным в обслуживании.
  • Простота. Хуки обеспечивают более лаконичный и интуитивно понятный способ добавления состояния и другой логики в функциональные компоненты, что облегчает понимание и написание кода.
  • Гибкость. Хуки можно использовать для различных целей, например для управления вводом формы, получения данных из API и обработки побочных эффектов. Это обеспечивает большую гибкость и позволяет писать более сложные приложения.
  • Повышенная производительность. Хуки позволяют обмениваться состоянием и логикой между компонентами, что может повысить производительность приложений за счет уменьшения количества дублирующегося кода.

Далее мы погрузимся в мир пользовательских React-хуков. Основное внимание уделим изучению различных способов применения пользовательских хуков для повышения функциональности и общей производительности приложений React.

Чтобы получить пользовательский хук, нужно просто создать новую функцию, которая следует определенному соглашению об именах. Эта функция должна начинаться со слова “use”, за которым следует описательное имя хука. Функция должна возвращать состояние и любые другие значения, которые предназначены для обмена между компонентами.

Рассмотрим несколько примеров пользовательских хуков, которые реализуют некоторые часто встречающиеся шаблоны при разработке веб-приложения.

Вот простой пример пользовательского хука, который управляет состоянием для ввода формы:

import { useState } from 'react';

function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);

function handleChange(event) {
setValue(event.target.value);
}

return {
value,
onChange: handleChange,
};
}

export default useFormInput;

В приведенном примере пользовательский хук с именем useFormInput, которое является стандартным для хуков React, принимает аргумент initialValue и возвращает объект, содержащий текущее значение ввода и функцию handleChange. Эта функция handleChange обновляет значение ввода при каждом его изменении.

Чтобы применить этот пользовательский хук, можно импортировать его в компонент и использовать так же, как и любой другой хук:

import React from 'react';
import useFormInput from './useFormInput';

function Form() {
const name = useFormInput('');

return (
<div>
<input type="text" {...name} />
</div>
);
}

В этом примере хук useFormInput импортируется в компонент Form и используется для управления состоянием поля ввода имени. Spread-оператор …name используется для передачи значения и свойств onChange из хука в элемент ввода.

Пользовательские хуки можно использовать для различных целей, начиная от управления вводом формы и заканчивая получением данных из API.

Вариантов огромное множество, поэтому рассмотрим случай, когда нужно сделать сетевой запрос для получения данных из API. Это обычная задача в веб-разработке, которую можно решить в React с помощью встроенного хука useEffect. Однако, если эта логика необходима в нескольких компонентах, писать один и тот же код в каждом компоненте довольно утомительно. Вот тут-то и выручают пользовательские хуки.

Чтобы сделать код многоразовым, можно создать пользовательский хук, который инкапсулирует логику выполнения сетевого запроса. Вот пример того, как может выглядеть такой хук:

import { useState, useEffect } from 'react';

function useFetchData(url) {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);

useEffect(() => {
setLoading(true);
fetch(url)
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, [url]);

return { data, error, loading };
}

export default useFetchData;

Этот пользовательский хук, называемый useFetchData, принимает параметр url и возвращает объект с тремя значениями: data, error, и loading. Эти значения представляют собой состояние сетевого запроса:

  • data содержит данные, возвращенные API;
  • error содержит ошибку, которая могла произойти;
  • loading указывает, выполняется ли запрос в данный момент.

Хук useEffect используется для выполнения сетевого запроса. Он принимает функцию, содержащую логику выполнения запроса, и массив зависимостей. В этом случае единственной зависимостью является url, что означает, что запрос будет выполнен только при изменении url. Хук useState используется для отслеживания состояния запроса, при этом data, error и loading представлены собственным значением состояния.

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

import React from 'react';
import { useFetchData } from './useFetchData';

function DataComponent({ url }) {
const { data, error, loading } = useFetchData(url);

if (loading) {
return <p>Loading...</p>;
}

if (error) {
return <p>An error occurred: {error.message}</p>;
}

return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}

В этом примере функциональный компонент DataComponent использует пользовательский хук useFetchData. Когда компонент рендерится, вызывается хук с параметром url, переданным в качестве свойства. Возвращенные хуком значения data, error и loading деструктурируются и используются для рендеринга соответствующего контента в зависимости от состояния сетевого запроса.

Другим распространенным шаблоном в веб-приложениях является управление пагинацией. Поэтому рассмотрим пример пользовательского хука для управления пагинацией:

import { useState, useEffect } from 'react';

const usePagination = (data, itemsPerPage) => {
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(Math.ceil(data.length / itemsPerPage));

useEffect(() => {
setTotalPages(Math.ceil(data.length / itemsPerPage));
}, [data, itemsPerPage]);

const changePage = (page) => {
setCurrentPage(page);
};

const prevPage = () => {
setCurrentPage(currentPage - 1);
};

const nextPage = () => {
setCurrentPage(currentPage + 1);
};

const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentData = data.slice(startIndex, endIndex);

return {
currentPage,
totalPages,
changePage,
prevPage,
nextPage,
currentData,
};
};

export default usePagination;

Этот пользовательский хук использует хуки useState и useEffect для управления текущей страницей и общим количеством страниц соответственно. Хук useEffect используется для пересчета общего количества страниц при изменении данных и элементов на странице.

Функция changePage переводит текущую страницу в переданный ей аргумент page. Функции prevPage и nextPage уменьшают и увеличивают номер текущей страницы.

Пользовательский хук вычисляет начальный и конечный индексы текущих данных и возвращает объект с текущей страницей, общим количеством страниц, change page, prev page, next page и текущими данными.

Чтобы применить пользовательский хук usePagination, просто импортируйте его в компонент и передайте данные и элементы для каждой страницы. Затем возвращенный объект можно деструктурировать и использовать так же, как и любой другой хук:

const PaginationExample = ({ data, itemsPerPage }) => {
const {
currentPage,
totalPages,
changePage,
prevPage,
nextPage,
currentData,
} = usePagination(data, itemsPerPage);

return (
<>
<ul>
{currentData.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<button onClick={prevPage} disabled={currentPage === 1}>
Prev
</button>
<button onClick={nextPage} disabled={currentPage === totalPages}>
Next
</button>
<select value={currentPage} onChange={(e) => changePage(Number(e.target.value))}>
{Array.from({ length: totalPages }, (_, i) => (
<option key={i + 1} value={i + 1}>
{i + 1}
</option>
))}
</select>
</>
);
};

export default PaginationExample;

В этом примере функциональный компонент PaginationExample использует пользовательский хук usePagination. При рендеринге компонента вызывается хук с параметрами data и itemsPerPage, переданными в качестве свойств. currentData возвращается хуком и применяется для рендеринга элементов на текущей странице. Функции prevPage и nextPage используются для перемещения вперед и назад по страницам. 

Выбрать определенный номер страницы немного сложнее. Тут используются следующие функции: currentPage  —  для отображения номера текущей страницы, changePage  —  для установки текущей страницы на определенный номер и totalPages  —  для отображения опций выбора, содержащих номера страниц.

Заключение

Мир пользовательских хуков React огромен и интересен. Он предлагает разработчикам много возможностей для улучшения функциональности, производительности и общей поддерживаемости приложений. Пользовательские хуки помогают выполнять самые разные операции  —  от управления вводом и состоянием формы до обмена логикой между компонентами. Они стали основным инструментом для многих разработчиков React.

Пользовательские хуки оптимизируют разработку и помогают создавать более динамичные и эффективные приложения как новичкам, так и профессионалам.

Ресурсы

Шаблонов, которые можно реализовать с помощью пользовательских хуков, гораздо больше, чем приведено в этой статье. Доступ к некоторым из них открывают следующие библиотеки:

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Sebastian: Creating Custom React Hooks: The Ultimate Guide

Предыдущая статьяКак использовать инструменты статического анализа в коде Python
Следующая статьяКласс данных в Kotlin