{"id":188,"date":"2025-08-28T14:48:17","date_gmt":"2025-08-28T14:48:17","guid":{"rendered":"https:\/\/learn.rantissi.my.id\/?p=188"},"modified":"2025-08-28T14:48:19","modified_gmt":"2025-08-28T14:48:19","slug":"membangun-frontend-web3-dengan-react-ethers-js","status":"publish","type":"post","link":"https:\/\/learn.rantissi.my.id\/index.php\/2025\/08\/28\/membangun-frontend-web3-dengan-react-ethers-js\/","title":{"rendered":"Membangun Frontend Web3 dengan React + Ethers.js"},"content":{"rendered":"\n<p>Kita akan membuat halaman web sederhana yang:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Menampilkan semua pesan dari smart contract<\/li>\n\n\n\n<li>Punya form untuk <strong>mengirim pesan ke blockchain<\/strong><\/li>\n\n\n\n<li>Terkoneksi langsung ke <strong>MetaMask<\/strong> dan <strong>Sepolia Testnet<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Persiapan Awal<\/h2>\n\n\n\n<p>\ud83d\udcc2 Kembali ke direktori root, lalu buat project React baru:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-react-app frontend\ncd frontend\nnpm install ethers\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Struktur Folder<\/h2>\n\n\n\n<p>Pastikan kamu sekarang punya struktur seperti ini:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>hello-web3\/\n\u251c\u2500\u2500 contracts\/\n\u251c\u2500\u2500 scripts\/\n\u251c\u2500\u2500 hardhat.config.js\n\u2514\u2500\u2500 frontend\/\n    \u251c\u2500\u2500 public\/\n    \u2514\u2500\u2500 src\/\n        \u2514\u2500\u2500 App.js\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Ganti Isi <code>App.js<\/code> dengan Kode Ini<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import React, { useEffect, useState } from \"react\";\nimport { ethers } from \"ethers\";\nimport \".\/App.css\";\n\n\/\/ Ganti dengan alamat kontrakmu sendiri!\nconst contractAddress = \"0x123...ABC\";\nconst abi = &#91;\n  {\n    \"inputs\": &#91;{\"internalType\": \"string\",\"name\": \"_message\",\"type\": \"string\"}],\n    \"name\": \"sendMessage\",\n    \"outputs\": &#91;],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": &#91;],\n    \"name\": \"getAllMessages\",\n    \"outputs\": &#91;{\"internalType\": \"string&#91;]\",\"name\": \"\",\"type\": \"string&#91;]\"}],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  }\n];\n\nfunction App() {\n  const &#91;currentAccount, setCurrentAccount] = useState(\"\");\n  const &#91;messages, setMessages] = useState(&#91;]);\n  const &#91;input, setInput] = useState(\"\");\n\n  const checkWallet = async () =&gt; {\n    if (window.ethereum) {\n      const accounts = await window.ethereum.request({ method: \"eth_requestAccounts\" });\n      setCurrentAccount(accounts&#91;0]);\n    } else {\n      alert(\"Install MetaMask dulu ya!\");\n    }\n  };\n\n  const fetchMessages = async () =&gt; {\n    const provider = new ethers.providers.Web3Provider(window.ethereum);\n    const contract = new ethers.Contract(contractAddress, abi, provider);\n    const data = await contract.getAllMessages();\n    setMessages(data);\n  };\n\n  const sendMessage = async () =&gt; {\n    if (!input) return;\n    const provider = new ethers.providers.Web3Provider(window.ethereum);\n    const signer = provider.getSigner();\n    const contract = new ethers.Contract(contractAddress, abi, signer);\n    const tx = await contract.sendMessage(input);\n    await tx.wait();\n    setInput(\"\");\n    fetchMessages();\n  };\n\n  useEffect(() =&gt; {\n    checkWallet();\n    fetchMessages();\n  }, &#91;]);\n\n  return (\n    &lt;div className=\"App\"&gt;\n      &lt;h2&gt;\ud83d\udce8 Message Portal Web3&lt;\/h2&gt;\n      &lt;p&gt;Wallet: {currentAccount || \"Belum terhubung\"}&lt;\/p&gt;\n      &lt;input\n        placeholder=\"Ketik pesanmu...\"\n        value={input}\n        onChange={(e) =&gt; setInput(e.target.value)}\n      \/&gt;\n      &lt;button onClick={sendMessage}&gt;Kirim&lt;\/button&gt;\n      &lt;h3&gt;Semua Pesan:&lt;\/h3&gt;\n      &lt;ul&gt;\n        {messages.map((msg, idx) =&gt; (\n          &lt;li key={idx}&gt;\ud83d\udcdd {msg}&lt;\/li&gt;\n        ))}\n      &lt;\/ul&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Jalankan Frontend Web3<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>npm start\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udd17 Akses di <code>http:\/\/localhost:3000<\/code><br>\ud83d\udca1 MetaMask akan muncul minta konfirmasi transaksi saat kamu mengirim pesan!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Tips Tambahan<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Jangan lupa <strong>ganti <code>contractAddress<\/code><\/strong> di kode dengan alamat kontrakmu<\/li>\n\n\n\n<li>Kamu bisa <strong>ubah gaya UI<\/strong> sesuka hati di <code>App.css<\/code><\/li>\n\n\n\n<li>Pastikan jaringan MetaMask kamu ada di <strong>Sepolia<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Ringkasan<\/h2>\n\n\n\n<p>\u2705 Kamu sudah punya aplikasi Web3 lengkap:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Smart Contract: <code>MessagePortal.sol<\/code><\/li>\n\n\n\n<li>Frontend React yang bisa baca dan kirim data ke blockchain<\/li>\n\n\n\n<li>Terhubung ke wallet pengguna (MetaMask)<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kita akan membuat halaman web sederhana yang: Persiapan Awal \ud83d\udcc2 Kembali ke direktori root, lalu buat project React baru: Struktur Folder Pastikan kamu sekarang punya struktur seperti ini: Ganti Isi App.js dengan Kode Ini Jalankan Frontend Web3 \ud83d\udd17 Akses di http:\/\/localhost:3000\ud83d\udca1 MetaMask akan muncul minta konfirmasi transaksi saat kamu mengirim pesan! Tips Tambahan Ringkasan \u2705&#8230;<\/p>\n","protected":false},"author":1,"featured_media":24,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-188","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web3-blockchain"],"_links":{"self":[{"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/posts\/188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/comments?post=188"}],"version-history":[{"count":1,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/posts\/188\/revisions"}],"predecessor-version":[{"id":189,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/posts\/188\/revisions\/189"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/media\/24"}],"wp:attachment":[{"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/media?parent=188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/categories?post=188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/learn.rantissi.my.id\/index.php\/wp-json\/wp\/v2\/tags?post=188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}