Как Tanstack Query превратил data layer в dashboard для инвестора в недвижимость

#react#tanstack-query#data-fetching#real-world-case

Мой друг, инвестор в rental properties, замучил меня сообщениями: «Эй, это хорошая сделка?» — и скриншотом с Zillow. После 30-го такого запроса я решил автоматизировать процесс и собрал для него property analysis dashboard. Но неожиданно главным героем проекта стала не бизнес-логика, а Tanstack Query, который сделал data layer почти невидимым.

Бекенд как proxy, фронтенд как кэширующий слой

Серверная часть — это express-прокси для Zillow API (через сторонний сервис ZillApi). На входе адрес, на выходе 300+ полей: zestimate, rent estimates, tax history. Бекенд добавляет лишь deal score — мою формулу оценки выгодности сделки.

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

function useProperty(address: string) {
  return useQuery({
    queryKey: ['property', address],
    queryFn: () => fetch(`/api/property/${address}`).then(r => r.json()),
    staleTime: 1000 * 60 * 60, // 1 hour
    enabled: !!address,
  });
}

Что здесь важно:

Параллельные запросы без boilerplate

Настоящий вызов начался с фичи сравнения 3-4 properties. Я ожидал кошмара с управлением состоянием параллельных запросов, но useQueries решил всё:

function useCompare(addresses: string[]) {
  return useQueries({
    queries: addresses.map(addr => ({
      queryKey: ['property', addr],
      queryFn: () => fetch(`/api/property/${addr}`).then(r => r.json()),
      staleTime: 1000 * 60 * 60,
    })),
  });
}

Что сработало идеально:

Оптимистичные updates как бонус

Для сохранения избранных properties добавил useMutation с optimistic updates:

const saveMutation = useMutation({
  mutationFn: (property) => fetch('/api/saved', {
    method: 'POST',
    body: JSON.stringify(property),
  }),
  onMutate: async (newProperty) => {
    await queryClient.cancelQueries({ queryKey: ['saved'] });
    const previous = queryClient.getQueryData(['saved']);
    queryClient.setQueryData(['saved'], old => [...old, newProperty]);
    return { previous };
  },
  onError: (err, vars, context) => {
    queryClient.setQueryData(['saved'], context.previous);
  },
  onSettled: () => {
    queryClient.invalidateQueries({ queryKey: ['saved'] });
  },
});

Вся логика — 15 строк вместо типичных 50+ с useReducer. При этом:

Что это дало на практике

  1. Скорость разработки: весь data layer уместился в 40 строк против ~100 с классическим подходом
  2. UX «из коробки»: кэширование, background refetch, deduplication запросов
  3. Лёгкий рост: когда другие инвесторы попросили доступ, добавление auth (через Clerk) не сломало логику

Где Tanstack Query не silver bullet:

Что попробовать дальше

Если ваш проект:

— Tanstack Query сэкономит вам десятки часов. В моём случае он превратил dashboard из «одноразового инструмента» в продукт, которым пользуются несколько инвесторов ежедневно. И всё это — без перфоманс-оптимизаций вручную.


Источник: https://www.reddit.com/r/reactjs/comments/1twnc3a/built_a_property_analysis_dashboard_for_a_friend/