Хук должен связывать ответ с текущим URL, очищать предыдущий запрос и отдельно возвращать загрузку и ошибку.
Реализуйте на TypeScript хук `usePage`, который принимает URL, загружает данные пользователя, возвращает `data`, `loading` и `error`, повторяет запрос при изменении URL и корректно отменяет запрос при размонтировании компонента или смене URL.
Хук должен связывать ответ с текущим URL, очищать предыдущий запрос и отдельно возвращать загрузку и ошибку.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Хук должен связывать ответ с текущим URL, очищать предыдущий запрос и отдельно возвращать загрузку и ошибку.
Пример ожидает пользователя с id и name:
import { useEffect, useState } from 'react';
type User = { id: string | number; name: string };
type PageState = { data: User | null; loading: boolean; error: string | null };
export function usePage(url: string): PageState {
const [saved, setSaved] = useState<{ url: string; state: PageState }>({
url, state: { data: null, loading: true, error: null }
});
useEffect(() => {
const controller = new AbortController();
let active = true;
setSaved({ url, state: { data: null, loading: true, error: null } });
async function load() {
try {
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) throw new Error('Ошибка загрузки');
const value: unknown = await response.json();
if (!value || typeof value !== 'object' || !('id' in value) ||
!('name' in value) || typeof value.name !== 'string' ||
(typeof value.id !== 'number' && typeof value.id !== 'string')) {
throw new Error('Некорректный ответ');
}
const data: User = { id: value.id, name: value.name };
if (active) setSaved({ url, state: { data, loading: false, error: null } });
} catch (error) {
if (active && !controller.signal.aborted) setSaved({ url, state: {
data: null, loading: false,
error: error instanceof Error ? error.message : 'Ошибка загрузки'
} });
}
}
load();
return () => { active = false; controller.abort(); };
}, [url]);
return saved.url === url ? saved.state : { data: null, loading: true, error: null };
}
Проверка URL не позволяет показать прежнего пользователя даже в рендере перед запуском нового эффекта.