Membangun fondasi proyek DApp dari awal: scaffold React/TypeScript dengan Vite, install wagmi dan viem, konfigurasi chains mainnet dan testnet, serta menyiapkan struktur hooks useReadContract, useWriteContract, dan connect wallet

Setelah di episode 8 kita menyiapkan toolchain contract, pada episode ini kita membangun fondasi DApp frontend. Di sinilah series bergeser dari teori ke kode yang benar-benar berjalan di browser kalian.
Mengapa episode ini penting? Karena arsitektur awal menentukan segalanya: konfigurasi wagmi yang salah akan membuat semua hook gagal dengan error yang membingungkan. Menyiapkan proyek dengan benar — vite, wagmi, viem, chains, dan provider — adalah setengah dari debugging yang akan kalian hindari di episode 10-12.
Mulai dari proyek React + TypeScript:
npm create vite@latest my-dapp -- --template react-ts
cd my-dapp
npm installInstall dependensi Web3:
npm install wagmi viem @tanstack/react-queryviem adalah library low-level (jaringan, transaksi, kontrak); wagmi adalah lapisan hooks React di atasnya; @tanstack/react-query dibutuhkan wagmi untuk caching data on-chain.
Buat file konfigurasi yang menghubungkan chains dan transport:
import { http, createConfig } from "wagmi"
import { mainnet, sepolia, base, baseSepolia } from "wagmi/chains"
export const wagmiConfig = createConfig({
chains: [mainnet, sepolia, base, baseSepolia],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
[base.id]: http(),
[baseSepolia.id]: http(),
},
})Hal penting:
http() memakai RPC default publik — cukup untuk development; di episode 15 kita ganti dengan API key provider untuk produksi.createConfig menerima banyak chains sekaligus; wagmi otomatis paham chain mana yang aktif dari wallet.functionName.Bungkus aplikasi dengan WagmiProvider dan QueryClientProvider:
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import { WagmiProvider } from "wagmi"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { wagmiConfig } from "./wagmi"
import App from "./App"
const queryClient = new QueryClient()
createRoot(document.getElementById("root")!).render(
<StrictMode>
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</WagmiProvider>
</StrictMode>,
)Tanpa kedua provider ini, semua hook wagmi akan melempar error "wagmi: must be used within WagmiProvider".
Setelah fondasi siap, tiga pola yang akan kalian pakai terus:
| Hook | Fungsi | Episode |
|---|---|---|
useConnect / useAccount | Connect wallet & membaca akun aktif | 10 |
useReadContract | Memanggil fungsi read (tanpa gas) | 11 |
useWriteContract | Mengirim transaksi (write) | 11 |
useWatchContractEvent | Mendengarkan event on-chain | 12 |
Semua hook ini membaca konfigurasi dari WagmiProvider — kalian tidak perlu menurunkan config manual di setiap komponen.
Address kontrak bersifat per-chain. Pola yang benar — jangan hardcode satu address:
import type { Address } from "viem"
export const TOKEN_ADDRESSES: Record<number, Address> = {
[1]: "0x0000000000000000000000000000000000000001", // mainnet
[84532]: "0x0000000000000000000000000000000000000002", // base sepolia
}
export function getTokenAddress(chainId: number): Address {
const address = TOKEN_ADDRESSES[chainId]
if (!address) throw new Error(`Token tidak ter-deploy di chain ${chainId}`)
return address
}Pola ini memastikan aplikasi kalian tahu harus bicara ke kontrak mana di chain mana — dan memberi error yang jelas jika user berada di chain yang salah (kita tangani UX-nya di episode 10).
Tip
Simpan address dan ABI contract dari hasil deploy (Remix atau forge create) ke file contracts.ts. Saran praktis: panggil ABI lewat import dari file terpusat (misalnya output forge / typechain), bukan menyalin-tempel manual — sekali copy-paste salah, selector akan mismatch dan transaksi gagal di rantai.
Jalankan dev server dan pastikan tidak ada error saat build:
npm run dev
npx tsc --noEmitJika tsc bersih dan halaman terbuka, fondasi DApp kalian sudah benar — siap untuk connect wallet di episode 10.
Rangkuman yang sudah kalian pelajari di episode 9:
createConfig mendaftarkan chains & transports; http() cukup untuk development.contracts.ts.Inti yang harus dibawa pulang:
Di episode 10 selanjutnya, kita membahas connect wallet & account management — useConnect/useAccount, injected provider MetaMask, WalletConnect QR, switch network, deteksi chain, serta disconnect/reconnect untuk UX yang halus. Sampai jumpa di episode 10!