Розробка фронтенду dApp на Next.js

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка фронтенду dApp на Next.js
Середній
~1-2 тижні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    920
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    885

Розробка фронтенда dApp на Next.js

Next.js для Web3 — це не тільки SSR/SSG. Це перш за все рішення конкретного протиріччя: дані блокчейну вимагають client-side execution (підключення гаманця, підпис трансакцій), а SEO та початкова загрузка вимагають серверного рендерингу. Неправильна межа між server та client компонентами ломає або wallet integration, або производительність.

Архітектура: розділення server та client

Проблема гідрації з wagmi/viem

wagmi 2.x використовує localStorage та window.ethereum — обидва об'єкти недоступні на сервері. Наївний імпорт useAccount у Server Component викликає помилку. Ще гірше — hydration mismatch: сервер рендерить «не підключений», клієнт після гідрації показує «підключений до MetaMask», і React видає warning або ломає UI.

Правильна структура:

// app/providers.tsx — CLIENT компонент, оборачує всё додаток
'use client';

import { WagmiProvider, createConfig, http } from 'wagmi';
import { mainnet, base, arbitrum } from 'wagmi/chains';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ConnectKitProvider } from 'connectkit';

const config = createConfig({
  chains: [mainnet, base, arbitrum],
  transports: {
    [mainnet.id]: http(process.env.NEXT_PUBLIC_RPC_MAINNET),
    [base.id]: http(process.env.NEXT_PUBLIC_RPC_BASE),
    [arbitrum.id]: http(process.env.NEXT_PUBLIC_RPC_ARBITRUM),
  },
});

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <ConnectKitProvider>{children}</ConnectKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}
// app/layout.tsx — SERVER компонент, імпортує Providers
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Статичний контент (navbar, footer, landing text) — Server Components. Гаманець, баланси, кнопки трансакцій — Client Components з 'use client'.

SSR для on-chain даних

Публічні дані блокчейну (TVL протоколу, список токенів, ціни) можна загружати на сервері. Next.js 14 Server Components + fetch з кешуванням:

// app/protocol/page.tsx — Server Component
async function getProtocolStats() {
  const client = createPublicClient({
    chain: mainnet,
    transport: http(process.env.RPC_URL), // приватна змінна, не NEXT_PUBLIC_
  });

  const [tvl, totalUsers] = await Promise.all([
    client.readContract({ address: PROTOCOL, abi, functionName: 'getTVL' }),
    client.readContract({ address: PROTOCOL, abi, functionName: 'userCount' }),
  ]);

  return { tvl, totalUsers };
}

export default async function ProtocolPage() {
  const stats = await getProtocolStats(); // виконується на сервері
  return <StatsDisplay stats={stats} />;
}

fetch у Next.js 14 кешується за замовчуванням. Для on-chain даних через viem потрібне явне управління: revalidate: 60 в export const revalidate або ручна інвалідація через Route Handlers.

Управління станом трансакцій

Lifecycle трансакції в UI

Трансакція проходить кілька станів: idle → preparing → signing → pending → confirming → success/error. Кожен стан вимагає окремого UI feedback. wagmi надає хуки для кожного етапу:

function TransactionButton({ tokenId }: { tokenId: bigint }) {
  const { writeContract, data: hash, isPending, error } = useWriteContract();
  const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash });

  if (isPending) return <Button disabled>Підтвердіть у гаманці...</Button>;
  if (isConfirming) return <Button disabled>Очікування підтвердження ({hash?.slice(0, 8)}...)</Button>;
  if (isSuccess) return <Button variant="success">Готово ✓</Button>;

  return (
    <Button
      onClick={() => writeContract({ address: CONTRACT, abi, functionName: 'mint', args: [tokenId] })}
    >
      Mint
    </Button>
  );
}

Оптимістичні оновлення

Для операцій з передбачуваним результатом (like, follow, simple toggle) — оптимістичний UI через @tanstack/react-query useMutation з onMutate/onError/onSettled. Користувач бачить зміну негайно, откат відбувається тільки при помилці.

Multicall та batch запити

Для dashboard з множеством on-chain даних — ніяких паралельних одиночних RPC викликів. Multicall3 збирає всі запити в один:

const results = await publicClient.multicall({
  contracts: tokenIds.map(id => ({
    address: NFT_CONTRACT,
    abi: erc721Abi,
    functionName: 'tokenURI',
    args: [id],
  })),
});

viem підтримує multicall нативно. Для 100 токенів — 1 RPC запрос замість 100. Це різниця між 2 секундами та 200 мілісекундами загрузки dashboard.

Важливі деталі окруження

.env.local для локальної розробки, .env.production для продакшену. Змінні без NEXT_PUBLIC_ не попадають у клієнтський бандл — RPC URLs з API ключами повинні бути без префіксу (використовувати тільки в Server Components або Route Handlers).

RPC провайдери: Alchemy, Infura, QuickNode. Для продакшену — кілька провайдерів з fallback через wagmi fallback transport. Публічні RPC (вроде https://eth.llamarpc.com) мають rate limits — не використовувати в production без fallback.

Stack

Next.js 14+ (App Router), wagmi 2.x, viem 2.x, ConnectKit або RainbowKit, @tanstack/react-query 5.x, TypeScript, Tailwind CSS. Тестування: Vitest + Playwright для e2e. Деплой: Vercel (нативна підтримка Next.js) або самостійний деплой на Docker.

Орієнтири по строкам

Базовий dApp frontend з підключенням гаманця, читанням контракту та формами для трансакцій — 1 тиждень. З SSR для публічних даних, оптимістичними оновленнями, повним lifecycle трансакцій та мобільною адаптацією — 2 тижні.