使用 React 构建 web3 前端
介绍
在之前的教程中,我们介绍了如何从零开始创建和部署 NFT 收藏品智能合约。我们还探讨了如何在 etherscan 上验证合约,以及如何让您和您的用户直接从合约的 etherscan 页面调用函数。
然而,大多数严肃的项目倾向于部署自己的网站并允许用户直接从网站上进行铸造。
这正是我们在本教程中要讲解的内容。更具体地说,本教程将向您展示如何:
- 让用户将他们的 Metamask 钱包连接到您的网站
- 允许用户调用合约函数、进行付款并从您的收藏中铸造 NFT。
完成本教程后,您将拥有一个使用 React 构建的功能齐全的 Web3 前端。您还将获得构建任何通用 Web3 前端(除了 NFT 铸币器)所需的基础知识。
先决条件
本教程假设您已经开发并部署了智能合约到 Rinkeby 测试网络。如果您还没有,我们强烈建议您阅读本教程。为了学习本教程,您需要以下信息:
- 您的智能合约的 ABI 文件(可在您的智能合约项目的artifacts文件夹中找到)。
- 您的智能合约的地址。
我们还假设您有使用 React 和 JavaScript 的经验。如果没有,我们强烈建议您先阅读React 官网上的官方教程。
设置项目
让我们首先使用创建一个 React 项目create-react-app
。打开终端并运行以下命令:
npx create-react-app nft-collectible-frontend
安装过程大约需要 2 到 10 分钟。完成后,请运行以下命令检查一切是否正常:
cd nft-collectible-frontend
npm start
如果一切顺利,你应该会看到浏览器在localhost://3000 处打开一个新标签页,并显示以下屏幕。非常标准的 React 代码。
现在让我们做一些清理工作。
前往public/index.html
并更改您网站的标题和元描述。此步骤是可选的。
接下来,转到 src 文件夹并删除App.test.js
、logo.svg
和setupTests.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 文件,请转到您的安全帽项目并导航到artifacts/contracts/NFTCollectible.sol/NFTCollectible.json
。
我们现在需要将 JSON 文件复制到我们的 React 项目中。在文件夹contracts
中创建一个名为 的新文件夹src
并粘贴该NFTCollectible.json
文件。
您应该已经拥有已部署智能合约的地址。(如果没有,只需再次将其部署到 Rinkeby,并获取最新的地址和 ABI 文件)。
我们在上一篇教程中提到的合约地址是 0x355638a4eCcb777794257f22f50c289d4189F245。本教程中我们也将使用这个合约。
现在让我们导入合约 ABI 并在App.js
文件中定义合约地址。
设置样板 HTML、CSS 和 JS
我们的网站将极其简洁。它只有一个标题和一个“连接钱包”按钮。一旦钱包连接成功,“连接钱包”按钮将被替换为Mint NFT按钮。
我们不需要创建单独的组件文件。相反,我们将把所有 HTML 和逻辑App.js
以及所有 CSS 都写在App.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 套件。Moralis和web3modal等现成的解决方案允许您仅用几行代码即可添加对多个钱包的支持。但在本项目中,我们将专注于从头开始实现连接钱包的功能。我们将在后续教程中介绍 Moralis 等解决方案。
我们假设您已在浏览器中安装了 Metamask 钱包扩展程序。如果已安装,Metamask 会将一个ethereum
对象注入到您浏览器的全局window
对象中。我们将访问window.ethereum
该对象来执行大部分功能。
检查 Metamask 钱包是否存在
如果没有 Metamask 钱包,用户无法在我们的网站上铸造 NFT。让我们checkWalletIsConnected
在App
组件中填充一个函数,用于检查 Metamask 钱包是否存在。
请注意,我们还定义了useEffect
在 App 组件加载时检查 Metamask 是否存在的钩子。
在应用的 localhost 页面上打开控制台。如果您已安装 Metamask,您应该会看到一条消息“钱包已存在!我们准备好了!”
以编程方式连接 Metamask
安装了 Metamask 扩展程序并不意味着 Metamask 会自动连接到我们访问的每个网站。我们需要提示 Metamask 并让其主动通知用户。
这就是Connect Wallet功能的用武之地。它相当于 Web3 中的登录按钮。它允许用户通过网站前端连接并发送合约函数调用请求。
Metamask 通过该方法使这个过程变得非常简单window.ethereum.request
。
首先,让我们App()
使用 useState 钩子定义一个变量,用于跟踪用户的钱包地址。(别忘了useState
从 React 导入!)
const [currentAccount, setCurrentAccount] = useState(null);
现在,让我们定义该connectWalletHandler
函数。
让我们简单了解一下这个函数的作用。
- 它会检查您是否安装了 Metamask。如果没有,网站会弹出一个窗口,要求您安装 Metamask。
- 它向 Metamask 请求用户的钱包地址。
- 一旦用户同意连接网站,它就会获取第一个可用的钱包地址并将其设置为 currentAccount 变量的值。
- 如果出现问题(例如用户拒绝连接),它会失败并向控制台打印错误消息。
目前,如果您在您的网站上打开 Metamask 扩展程序,它会告诉您未连接。
现在到了关键时刻。点击您网站上的“连接钱包”按钮。Metamask 会提示您连接网站。同意连接后,您的扩展程序屏幕将如下所示。
恭喜!我们已成功将钱包连接到我们的网站。
一旦钱包连接成功,我们最好将“连接钱包”按钮替换为Mint NFT按钮。在 App 的返回值中,我们将“连接钱包”按钮的渲染替换为条件渲染。
{currentAccount ? mintNftButton() : connectWalletButton()}
我们的网站现在应该是这样的:
让我们刷新页面并检查我们的扩展程序。你会看到 Metamask 告诉我们我们仍然连接到该网站,但我们的网站仍然显示“连接钱包”按钮。
如果你熟悉 React,你应该明白为什么会发生这种情况。毕竟,我们currentAccount
只在connectWallet
函数内部设置状态。
理想情况下,网站应该在每次App
加载组件时(即每次刷新时)检查钱包是否已连接。
让我们扩展该checkWalletIsConnected
功能,以便在网站加载后立即检查帐户,如果钱包已经连接,则设置 currentAccount。
(请注意,我们已将此函数标记为 async )。让我们简单介绍一下此函数的功能:
- 它检查 Metamask 是否已安装并将结果输出到控制台。
- 它尝试向 Metamask 请求已连接的帐户。
- 如果 Metamask 已连接,它会向该函数提供一个账户列表。如果没有连接,则返回一个空列表。
- 如果列表不为空,该函数将选择 Metamask 发送的第一个帐户并将其设置为当前帐户。
如果您现在刷新页面,您将看到该网站确实按应有的方式显示了Mint NFT按钮。
从网站上铸造 NFT
现在让我们实现网站的核心功能。当用户点击Mint NFT按钮时,我们预期会发生以下情况:
- Metamask 提示用户支付 NFT 的价格 + gas。
- 一旦用户接受,Metamask 就会代表用户调用我们合约的 mintNFT 函数。
- 一旦交易完成,它会通知用户交易成功/失败。
为此,我们需要ethers
智能合约项目中的库。在终端中,运行以下命令:
npm install ethers
让我们导入这个库App.js
。
import { ethers } from 'ethers';
最后,让我们填充该mintNftHandler
函数。
(不要忘记将此功能标记为async
)
像往常一样,让我们来谈谈这个函数的作用。
- 它尝试访问 Metamask 注入的以太坊对象。
- 如果以太坊存在,它会将 Metamask 设置为 RPC 提供者。这意味着你将使用 Metamask 钱包向矿工发出请求。
- 要发出请求,用户需要使用其私钥对交易进行签名。为此,我们访问了签名者。
- 然后,我们使用已部署合约的地址、合约 ABI 和签名者启动一个 ethers 合约实例。
- 现在,我们可以通过上述合约对象调用合约上的函数。我们调用 mintNFT 函数,并请求 Metamask 发送 0.01 ETH(这是我们为 NFT 设定的价格)。
- 我们等待交易被处理,一旦完成,我们就将交易哈希输出到控制台。
- 如果出现任何失败(调用错误的函数、传递错误的参数、发送的 ETH < 0.01、用户拒绝交易等),则会在控制台上打印错误。
在您的网站上,打开浏览器的控制台,以便您能够实时查看挖掘状态。
现在,点击“铸造 NFT”按钮。Metamask 会提示您支付 0.01 ETH + gas。交易处理大约需要 15-20 秒。完成后,Metamask 弹窗和控制台输出都会确认交易。
您现在也可以在 Opensea 上查看 NFT 了。访问 testnets.opensea.io 上的帐户,您应该就能看到最新的 NFT。
用户体验改进和结论
恭喜!现在您已经拥有一个功能齐全的 web3 前端,用户可以用它来铸造 NFT。
然而,您可能已经注意到,该网站的用户体验有很多不足之处。以下是一些您可以考虑进行的改进。
确保用户连接到正确的网络
我们的网站假定用户在与我们的网站互动时已连接到 Rinkeby 网络。但情况可能并非总是如此。
能否实现一个功能,当用户未连接到 Rinkeby 时,会温和地提醒用户(就像 OpenSea 那样)?另外,确保用户在连接到错误的网络时看不到Mint NFT按钮。
显示交易状态
目前,我们的网站会将交易状态打印到控制台上。在实际项目中,您无法真正期望用户在与网站交互时打开控制台。
你能实现一个状态机制来追踪交易状态并实时向用户反馈吗?它应该在交易处理时显示加载器,在交易失败时通知用户,并在交易成功时显示交易哈希/Opensea 链接。
即使没有资金,也可以提示 Metamask
如果你的 Metamask 钱包中没有任何 ETH,点击“铸造 NFT”根本不会提示 Metamask。事实上,用户不会收到任何反馈。
你能确保即使用户资金不足,Metamask 也会收到提示吗?理想情况下,Metamask 应该会告知用户需要多少 ETH,以及用户还差多少 ETH。
其他生活质量变化
以下是您可以考虑的其他一些生活质量改变。
- 允许用户一次铸造多个 NFT。
- 从您的 NFT 收藏中添加一些样本艺术品。
- 在 Opensea 上添加指向您的收藏的链接。
- 添加经过验证的智能合约地址,以便人们可以仔细检查幕后真正发生的情况。
- 添加您的 Twitter、IG 和 Discord 的链接。
我们的 NFT 沙盒项目Rinkeby Squirrels实现了这里提到的大部分用户体验升级。您可以尝试在这里创建一个,看看它与我们构建的网站有何不同。
我们将在未来推出教程,向您展示如何实现其中一些升级。但我们强烈建议您亲自尝试一下。这样,您距离成为 Web3 前端大师就更近一步了。
如果您有任何疑问或遇到困难,请通过我们的Discord与我们联系。
如果您没有问题,欢迎随时来我们的Discord上和我们打个招呼!另外,如果您喜欢我们的内容,欢迎在推特上推荐我们、关注我们(@ScrappyNFTs 和 @Rounak_Banik),并邀请您的朋友加入我们的 Discord,我们将不胜感激。感谢您的支持!
最终代码库:https://github.com/rounakbanik/nft-collectible-frontend
关于 Scrappy Squirrels
Scrappy Squirrels集合了超过 10,000 种随机生成的 NFT。Scrappy Squirrels 面向 NFT 生态系统的新手买家、创作者和开发者。
该社区致力于了解 NFT 革命、探索其当前用例、发现新的应用程序以及寻找成员合作开展激动人心的项目。
加入我们的社区:https://discord.gg/8UqJXTX7Kd
文章来源:https://dev.to/rounakbanik/building-a-web3-frontend-with-react-340c