使用React创建一个web3的前端

2022-11-07 10:47:08 浏览数 (1)

译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3]

简介

在之前的教程[4]中,我们介绍了如何从头开始创建和部署一个 NFT 藏品智能合约。我们还探讨了如何在 etherscan 上验证我们的合约,并使自己和用户能够直接从合约的 etherscan 页面调用函数。

然而,大多数严肃的项目倾向于部署他们自己的网站,并允许用户直接从网站上铸币。

这正是我们将在本教程中涉及的内容。更具体地说,本教程将告诉你如何:

  1. 让用户将他们的 Metamask 钱包连接到网站上
  2. 允许用户调用一个合约函数,进行支付,并铸造一个 NFT。

在本教程结束时,你将拥有一个用 React 构建的功能齐全的 web3 前端。你也将获得构建任何通用的 web3 前端所需的基础知识(除了 NFT minter)。

前提

本教程假设你已经开发并部署了智能合约到 Rinkeby 测试网络。如果你还没有,我们强烈建议你通过本教程[5]。为了继续学习本教程,你将需要以下东西。

  1. 智能合约的 ABI 文件(可在你的项目的artifacts文件夹中找到)。
  2. 智能合约的地址。

我们还假设你有一些使用 React 和 Javascript 的经验。如果没有,强烈建议你先看一下React 网站的官方教程[6]

设置项目

让我们从使用create-react-app创建一个 React 项目开始。打开终端,运行以下命令:

代码语言:javascript复制
npx create-react-app nft-collectible-frontend

安装过程将需要 2-10 分钟。一旦完成后,通过运行以下命令检查一切是否正常。

代码语言:javascript复制
cd nft-collectible-frontend
npm start

如果一切顺利,你应该看到浏览器在localhost://3000[7]打开了一个新的标签,屏幕如下。很标准的 React 内容:

现在让我们做一些清理工作。

进入public/index.html,修改网站的标题和元描述(这一步是可选的)。

接下来,进入 src 文件夹,删除App.test.jslogo.svgsetupTests.js文件。在本教程中,我们将不需要这些文件。

进入App.js文件,用以下模板替换其内容。

代码语言:javascript复制
import './App.css';

function App() {
    return (
        <h1>Hello World</h1>
    );
}

export default App;

同时删除App.css的所有内容。但是,不要删除这个文件。在后面的章节中,我们将提供一些基本的风格设计,对这个演示项目来说应该是足够好了。

如果你回到 localhost,你应该看到一个屏幕,上面写着Hello World。我们现在有了一个基本的 react 项目,可以开始了。

获取合约 ABI 和地址

为了使我们的 React 前端能够与智能合约连接和通信,它需要合约的 ABI 和地址。

ABI(应用二进制接口)[8]是一个 JSON 文件,在合约编译过程中自动生成。我们部署到区块链上是以字节码的形式存储智能合约。为了在其上调用函数,传递正确的参数,并使用高级语言解析返回值,我们需要向前端指定有关函数和合约的细节(如名称、参数、类型等)。这正是 ABI 文件的作用。为了了解更多关于 ABI 的信息,建议你阅读:如何理解以太坊 ABI[9]

要找到你的 ABI 文件,请进入你的 hardhat 项目并导航到artifacts/contracts/NFTCollectible.sol/NFTCollectible.json

我们现在需要复制 JSON 文件到 React 项目。在src文件夹中创建一个名为contracts的新文件夹并粘贴NFTCollectible.json文件。

你应该已经有了部署的智能合约的地址。(如果你没有,只需再次将其部署到 Rinkeby,并获得最新的地址和 ABI 文件)。

我们在上一个教程中的合约地址是 0x355638a4eCcb777794257f22f50c289d4189F245。我们在本教程中也将使用这个合约。

现在让我们导入合约 ABI 并在App.js文件中定义合约地址。

设置模板 HTML、CSS 和 JS

网站将是非常简单的。它将只有一个标题和一个连接钱包按钮。一旦钱包被连接,连接钱包按钮将被一个Mint NFT按钮取代。

我们不打算费力地创建单独的组件文件。相反,我们将在App.js中编写所有的 HTML 和逻辑,在App.css中编写所有的 CSS。

将以下 Github gist 的内容复制到App.js文件中。

代码语言:javascript复制
import { useEffect } from 'react';
import './App.css';
import contract from './contracts/NFTCollectible.json';

const contractAddress = "0x355638a4eCcb777794257f22f50c289d4189F245";
const abi = contract.abi;

function App() {

  const checkWalletIsConnected = () => { }

  const connectWalletHandler = () => { }

  const mintNftHandler = () => { }

  const connectWalletButton = () => {
    return (
      <button onClick={connectWalletHandler} className='cta-button connect-wallet-button'>
        Connect Wallet
      </button>
    )
  }

  const mintNftButton = () => {
    return (
      <button onClick={mintNftHandler} className='cta-button mint-nft-button'>
        Mint NFT
      </button>
    )
  }

  useEffect(() => {
    checkWalletIsConnected();
  }, [])

  return (
    <div className='main-app'>
      <h1>Scrappy Squirrels Tutorial</h1>
      <div>
        {connectWalletButton()}
      </div>
    </div>
  )
}

export default App;

(记得在第 5 行设置正确的合约地址)

注意,这里已经定义了几个函数,这些函数目前没有什么作用。我们将在下面解释它们的用途,并在其中加入逻辑。

下面是相应的 CSS,将以下内容复制到你的App.css文件中。

代码语言:javascript复制
.main-app {
    text-align: center;
    margin: 100px;
}

.cta-button {
    padding: 15px;
    border: none;
    border-radius: 12px;
    min-width: 250px;
    color: white;
    font-size: 18px;
    cursor: pointer;
}

.connect-wallet-button {
    background: rgb(32, 129, 226);
}

.mint-nft-button {
    background: orange;
}

网站现在应该看起来像这样:

通过添加更多的样式和静态元素(图片、页眉、页脚、社交媒体链接等),可以自由地定制网站的外观。

我们已经把这个项目的大部分基础模块放在一起。现在处于一个很好的位置来解决本教程的第一个主要目标之一:允许用户将他们的钱包连接到我们的网站。

连接 Metamask 钱包

为了让用户能够从我们的合约中调用功能,他们需要能够将他们的钱包连接到我们的网站。钱包将使用户能够支付 Gas 和销售价格,以便从我们的集合中铸造一个 NFT。

在本教程中,我们将专门使用 Metamask 钱包和它的一套 API。有一些现成的解决方案,如Moralis[10]和web3modal[11],允许你用很少的代码添加对多个钱包的支持。但在这个项目中,我们将专注于从头开始实现连接钱包功能。在以后的教程中介绍 Moralis 等解决方案。

我们假设你已经在浏览器中安装了 Metamask 钱包插件。如果你有,Metamask 会将一个ethereum对象注入你的浏览器的全局window对象中。我们将访问window.ethereum来执行我们的大部分功能。

检查 Metamask 钱包是否存在

用户无法在我们的网站上铸造 NFT,除非他们有一个 Metamask 钱包。让我们在App组件中补充checkWalletIsConnected函数,检查 Metamask 钱包是否存在。

注意,我们还定义了useEffect钩子,当 App 组件加载时检查 Metamask 的存在。

在你的应用程序的 localhost 页面上打开控制台。如果你已经安装了 Metamask,你应该看到一条消息,说Wallet exists! We’re ready to go!(存在钱包!我们准备好了!)。

以程序方式连接 Metamask

仅仅因为我们安装了 Metamask 插件,并不意味着 Metamask 会自动连接到我们访问的每个网站。我们需要提示 Metamask 要求用户这样做。

这就是连接钱包功能的用武之地。它相当于 web3 的一个登录按钮。它允许用户通过网站连接并发送调用合约功能请求。

Metamask 通过 "window.ethereum.request"方法可以让连接变得简单。

让我们首先在App()中定义一个变量,用 useState 钩子来跟踪用户的钱包地址。(别忘了从 React 导入useState)

代码语言:javascript复制
const [currentAccount, setCurrentAccount] = useState(null);

现在,让我们定义connectWalletHandler函数。

让我们简单地看一下这个函数的作用:

  1. 检查是否安装了 Metamask。如果没有,网站会显示一个弹出窗口,要求安装 Metamask。
  2. 它请求 Metamask 提供用户的钱包地址。
  3. 一旦用户同意与网站连接,它将获取第一个可用的钱包地址,并将其作为 currentAccount 变量的值。
  4. 如果出了问题(比如用户拒绝连接),它就会失败,并在控制台打印出错误信息。

目前,如果你在网站上打开 Metamask 插件,它会显示 Not conntected(没有连接)。

现在关键时刻到了,点击网站上的*Connect Wallet(连接钱包)按钮。Metamask 将提示你与网站连接。一旦你同意,插件界面将看起来像这样:

恭喜你!已经成功地将钱包连接到网站。

一旦钱包被连接,我们最好用Mint NFT按钮取代Connect Wallet按钮。在 App 的返回值中,让我们用一个条件性的渲染来替换Connect Wallet按钮的渲染。

代码语言:javascript复制
{currentAccount ? mintNftButton() : connectWalletButton()}

网站现在应该看起来像这样:

让我们刷新页面并检查插件。你会看到 Metamask 显示连接了网站(connected),但网站仍然显示一个连接钱包的按钮。

如果你熟悉 React,应该很清楚为什么会发生这种情况。毕竟,我们只在 "connectWallet "函数中设置 "currentAccount "状态。

理想的情况是,网站应该在每次加载App组件时(即每次刷新时)检查钱包是否被连接。

让我们插件checkWalletIsConnected函数,在网站加载时立即检查账户,如果钱包已经连接,则设置 currentAccount。

(注意,这个函数标记为 async )。简单解释这个函数的作用:

  1. 它检查 Metamask 是否被安装,并将结果输出到控制台。
  2. 它试图为已连接的账户请求 Metamask。
  3. 如果 Metamask 已经连接了,它将通过给函数一个账户列表来完成。如果没有,则返回一个空列表。
  4. 如果列表不是空的,该函数将选择 Metamask 获取的第一个账户,并将其设置为当前账户。

如果你现在刷新页面,你会看到网站确实显示了Mint NFT按钮。

从网站上的 Mint NFT

现在让我们来实现网站的核心功能。当用户点击Mint NFT按钮时,我们希望发生以下情况。

  1. Metamask 提示用户支付 NFT 的价格 Gas。
  2. 一旦用户接受,Metamask 代表用户调用合约中的 mintNFT 功能。
  3. 一旦交易完成,它就会通知用户交易的成功/失败。

要做到这一点,我们将需要ethers库来进行合约交互。在你的终端,运行以下命令:

代码语言:javascript复制
npm install ethers

让我们在App.js中导入这个库:

代码语言:javascript复制
import { ethers } from 'ethers';

最后,让我们补充mintNftHandler函数:

(别忘了把这个函数标记为 "async")

像往常一样,解释一下这个函数的作用:

  1. 试图访问由 Metamask 注入的ethereum对象。
  2. 如果ethereum对象存在,它将 Metamask 设置为 RPC 提供者。这意味着,将使用 Metamask 钱包向矿工发出请求。
  3. 为了发出交易请求,用户需要使用他们的私钥签署交易。因此获取签名器。
  4. 然后使用部署的合约的地址、合约 ABI 和签名者创建一个合约实例。
  5. 通过上述合约对象调用我们合约上的函数。调用 mintNFT 函数并请求 Metamask 发送 0.01 ETH(这是我们为 NFT 设定的价格)。
  6. 等待交易被处理,一旦处理完毕,将交易哈希值输出到控制台。
  7. 如果有任何失败(错误的函数调用,错误的参数传递,<0.01 ETH 发送,用户拒绝交易,等等),错误将被打印到控制台。

在网站上,打开浏览器的控制台,这样你就能实时查看挖矿状态。

现在,点击Mint NFT按钮。Metamask 将提示你支付 0.01 ETH gas。该交易将需要大约 15-20 秒的时间来处理。一旦完成,交易可以通过 Metamask 的弹出窗口和控制台的输出来确认。

你现在也可以在 Opensea 上查看 NFT 了。导航到你在 testnets.opensea.io 上的账户[12],你应该可以看到你的最新 NFT。

用户体验的改进和结论

祝贺你!你现在有了一个功能齐全的 web3 前端,用户可以通过它来铸造 NFT。

然而,正如你可能已经注意到的,网站的用户体验还有很多需要改进的地方。以下是你应该考虑做的一些改进。

确保用户连接到正确的网络

我们的网站假设用户在与网站交互时,已经连接到 Rinkeby 网络,这可能并不总是如此。

你能不能实现在用户没有连接到 Rinkeby 时提醒他(就像 OpenSea 那样)?另外,确保用户在连接到错误的网络时不能看到Mint NFT按钮。

显示交易状态

目前,我们的网站将交易状态打印到控制台。在一个真实的项目中,你不能指望你的用户在与网站交互的同时打开他们的控制台。

你能实现跟踪交易状态并实时反馈给用户的状态吗?当交易正在处理时,它应该显示一个加载提示(loading),如果交易失败则通知用户,如果交易成功则显示交易哈希(或 Opensea 链接)。

即使资金不足,也要提示 Metamask

如果你的 Metamask 钱包中没有任何 ETH,点击 Mint NFT 将完全不会提示 Metamask。事实上,用户将不会收到任何反馈。

你能确保在用户资金不足的情况下也能提示 Metamask 吗?最好是由 Metamask 来通知用户需要多少 ETH,以及他/她还差多少。

其他改进

这里有一些其他的改进,你可以考虑:

  1. 允许用户单次铸币超过 1 个 NFT。
  2. 从你的 NFT 藏品中添加一些艺术作品的样本。
  3. 添加一个链接,链接在 Opensea 上你的藏品信息。
  4. 添加经过验证的智能合约地址,以便人们可以仔细检查幕后真正发生的事情。
  5. 添加你的 Twitter、IG 和 Discord 的链接。

我们的 NFT 沙盒项目,Rinkeby Squirrels[13],实现了这里提到的大部分用户体验升级,你可以尝试铸造一个。

最终代码库:https://github.com/rounakbanik/nft-collectible-frontend

关于 Scrappy Squirrels

Scrappy Squirrels[14]是一个由 10,000 多个随机生成的 NFT 组成的集合。Scrappy Squirrels 是为那些对 NFT 生态系统完全陌生的买家、创作者和开发者准备的。

这个社区是围绕着学习 NFT 革命,探索其目前的使用案例,发现新的应用,并找到成员一起合作进行令人兴奋的项目而建立的。

在这里加入我们的社区:https://discord.gg/8UqJXTX7Kd


本翻译由 Duet Protocol[15] 赞助支持。

原文:https://dev.to/rounakbanik/building-a-web3-frontend-with-react-340c

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

翻译小组: https://learnblockchain.cn/people/412

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

之前的教程: https://dev.to/rounakbanik/writing-an-nft-collectible-smart-contract-2nh8

[5]

本教程: https://dev.to/rounakbanik/writing-an-nft-collectible-smart-contract-2nh8

[6]

React网站的官方教程: https://reactjs.org/tutorial/tutorial.html

[7]

localhost://3000: http://localhost:3000/

[8]

ABI(应用二进制接口): https://learnblockchain.cn/docs/solidity/abi-spec.html#json

[9]

如何理解以太坊ABI: https://learnblockchain.cn/2018/08/09/understand-abi

[10]

Moralis: https://moralis.io/

[11]

web3modal: https://www.npmjs.com/package/web3modal

[12]

导航到你在testnets.opensea.io上的账户: https://testnets.opensea.io/account

[13]

Rinkeby Squirrels: https://medium.com/scrappy-squirrels/getting-started-with-nft-collectibles-communities-for-free-24bab021a97

[14]

Scrappy Squirrels: https://www.scrappysquirrels.co/

[15]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

0 人点赞