Користувацькі хуки (Custom Hooks) — це потужні інструменти для зменшення дублювання коду, підвищення модульності та абстрагування спільної логіки в додатках на React. Користувацькі хуки за своєю суттю є комбінацією одного або кількох базових хуків React і завжди починаються з префікса "use". У цьому матеріалі я не заглиблюватимусь у деталі користувацьких хук, а зосереджуся на тому, як зробити користувацький хук універсальним. Більше інформації про користувацькі хуки можна знайти тут.
Що таке універсальний (Generic) користувацький хук?
Універсальний користувацький хук (Generic Custom Hook) — це React хук, який може працювати з будь-яким типом даних, приймаючи певну модель даних і функціональність як параметри. Використовуючи TypeScript для визначення універсальних типів, можна зробити ці хуки ще більш гнучкими та потужними. Таким чином, один користувацький хук може працювати з різними типами даних, запобігаючи помилкам через використання неправильних типів і забезпечуючи більш надійну структуру коду.
useFetch
При створенні універсального користувацького хука ми можемо використовувати параметри типів, такі як T
або ResponseModel
, RequestModel
.
import {useEffect, useState} from 'react';
type UseFetchPropType = {
/**
* Функція для виклику API та отримання даних.
* @param query Модель запиту для API.
* @returns Модель відповіді
*/
callData: (query?: RequestModel) => Promise;
/**
* Запит за замовчуванням для API.
*/
defaultPayload?: RequestModel;
};
const useFetch = ({
defaultPayload,
callData,
}: UseFetchPropType) => {
/**
* Стан для відстеження, чи зараз відбувається запит даних.
*/
const [isFetching, setIsFetching] = useState(true);
/**
* Стан для збереження отриманих даних.
*/
const [data, setData] = useState(undefined);
/**
* Стан для збереження поточних параметрів запиту.
*/
const [payload, setPayload] = useState(defaultPayload);
/**
* Стан для відстеження, чи є помилка.
*/
const [error, setError] = useState(false);
/**
* Ефект для отримання даних щоразу, коли змінюються параметри запиту.
*/
useEffect(() => {
setIsFetching(true);
callData(payload)
.then(res => {
setError(false);
setData(res);
})
.catch(() => {
setData(undefined);
setError(true);
})
.finally(() => {
setIsFetching(false);
});
}, [payload]);
/**
* Скидає параметри запиту на значення за замовчуванням.
*/
const resetQuery = () => {
setPayload(defaultPayload);
};
/**
* Оновлює параметри запиту з наданими значеннями.
* @param updates Частковий об'єкт, що містить властивості для оновлення в запиті.
*/
const updateQuery = (updates: RequestModel) => {
const updatedQuery: RequestModel = {
...payload,
...updates,
};
setPayload(updatedQuery);
};
return {data, payload, isFetching, error, resetQuery, updateQuery};
};
export {useFetch};
Цей хук можна використовувати з будь-яким типом ResponseModel (модель відповіді API) та RequestModel (параметри запиту), що дозволяє використовувати один і той самий хук useFetch
для різних API запитів.
Використання
Після того як ми передаємо функцію для виклику сервісу в якості параметра для хука useFetch
, а також визначаємо типи даних, ми можемо використовувати цей хук.
Як ви можете побачити в наведеному нижче прикладі, ми зберігаємо типи даних.
import React from 'react';
import {FlatList, ListRenderItemInfo, Pressable, Text} from 'react-native';
import {useFetch} from 'services/generalServices/useFecth';
type FilterModel = {
categorydId?: number;
brandId?: number;
};
type ProductModel = {
id: number;
name: string;
image: string;
price: number;
};
export const App = () => {
const {
data,
isFetching,
error,
updateQuery
} = useFetch({callData: getProducts});
function renderProductCard({item}: ListRenderItemInfo) {
return {item.name};
}
function renderEmptyView(item: ListRenderItemInfo) {
return <>;
}
const renderCategories = () => {
return (
updateQuery({categorydId: 1})}>
Categori
);
};
return error ? (
) : (
renderProductCard(item)}
ListEmptyComponent={!isFetching && data?.length === 0 ? renderEmptyView : null}
/>
);
};
Завершення
Універсальні користувацькі хуки (Generic Custom Hooks) підвищують повторне використання коду в додатках на React, дозволяючи створювати модульні та гнучкі структури, одночасно забезпечуючи типову безпеку (Type Safety). Такі хуки можуть бути використані для отримання даних через API, управління формами, роботи з локальним сховищем і багатьох інших завдань, а також можуть бути налаштовані відповідно до вашої архітектури проекту.
Сподіваюся, що я зміг додати нові знання до вашого арсеналу. Бажаю вам писати більш ефективний та чистий код. Успіхів у роботі!
Перекладено з: Generic Custom Hooks