使用React创建一个web3的前端

简介

本教程将告诉你如何:

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

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

前提

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

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

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

设置项目

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

npx create-react-app nft-collectible-frontend

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

cd nft-collectible-frontend
npm start

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

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

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

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

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

import './App.css';

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

export default App;

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

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

获取合约ABI和地址

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

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

要找到你的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文件中。

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文件中。

.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。有一些现成的解决方案,如Moralisweb3modal,允许你用很少的代码添加对多个钱包的支持。但在这个项目中,我们将专注于从头开始实现连接钱包功能。在以后的教程中介绍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)

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按钮的渲染。

{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库来进行合约交互。在你的终端,运行以下命令:

npm install ethers

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

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上的账户,你应该可以看到你的最新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,实现了这里提到的大部分用户体验升级,你可以尝试铸造一个。

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

关于 Scrappy Squirrels

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

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

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

猜你喜欢

转载自blog.csdn.net/smartContractXH/article/details/126704522