Собственный хук — это JavaScript-функция, имя которой начинается с "use", и которая может вызывать другие хуки. Кастомные хуки позволяют извлекать логику компонентов в переиспользуемые функции.
use
(например, useFetch
, useLocalStorage
)import { useState, useEffect } from 'react';
function useCustomHook(initialValue) {
const [value, setValue] = useState(initialValue);
useEffect(() => {
// Побочные эффекты
}, [value]);
// Возвращаем значения, которые будут доступны компоненту
return [value, setValue];
}
function useLocalStorage(key, initialValue) {
// Получаем значение из localStorage или используем initialValue
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
// Обновляем localStorage при изменении значения
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// Использование в компоненте
const [name, setName] = useLocalStorage('username', 'Гость');
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Ошибка загрузки данных');
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]); // Зависимость от URL
return { data, loading, error };
}
// Использование в компоненте
const { data, loading, error } = useFetch('https://api.example.com/data');
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []); // Эффект только при монтировании
return windowSize;
}
// Использование в компоненте
const { width, height } = useWindowSize();
Для тестирования хуков можно использовать библиотеку @testing-library/react-hooks:
import { renderHook } from '@testing-library/react-hooks';
import useCounter from './useCounter';
test('should increment counter', () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
Создание собственных хуков в React — это мощный способ организации и переиспользования логики между компонентами. Кастомные хуки позволяют создавать чистые, понятные и поддерживаемые компоненты, вынося сложную логику в отдельные функции. При создании хуков важно соблюдать правила хуков, обеспечивать гибкость API и обрабатывать возможные ошибки. Грамотно созданные хуки значительно упрощают разработку и тестирование React-приложений.