使用Drizzle编写DApp前台

1,017 阅读9分钟

框架通过提供开始构建任何前端应用程序所需的初始代码/设置和工具,使启动和配置网络项目变得更加容易和快捷。区块链和DApp开发的世界也不例外。

在本教程中,我们将向您展示如何使用Drizzle框架来构建以太坊上的前端应用程序。我们将研究一个实际的例子,其中我们将使用Drizzle与React一起构建一个DApp。

以下是我们将讨论的内容。

要轻松地理解我们在本教程中所涉及的概念,你需要有以下的基本知识。

什么是Drizzle?

Drizzle作为一个基于Truffle套件的框架。它是一个JavaScript库,为Web3、账户和合同实例化提供接口,以及额外的合同功能,并帮助布线必要的同步。

Drizzle是主库。它包含Drizzle的核心逻辑,并与您的应用程序手动集成。

Drizzle可以作为一个npm包安装,这意味着你需要在本地机器上安装Node.js,通过终端使用Node.js命令来安装Drizzle。

另外,您也可以使用Truffle Boxes来处理安装事宜。

Drizzle模块

Drizzle这个核心库为Web3和智能合约的前端应用提供了一个反应式存储。反应式存储与Redux存储相似,意味着它在检测到智能合约或用户界面的状态更新时自动更新。我们可以将Drizzle纳入任何基于JavaScript的项目中

有两个主要模块可以与Drizzle一起安装。这些模块提供的接口使构建DApps更容易。

  • Drizzle-react可以帮助你用Drizzle轻松引导React应用程序。它提供了一个DrizzleProvider 组件和drizzleConnect 辅助方法,使Drizzle与您的React应用程序的连接更容易。这些都是高阶的Provider 组件,有助于包裹我们应用程序中的其他组件,并将Drizzle的状态传递给它们。
  • Drizzle React Components提供了有用的React组件,这些组件是常见的DApp函数所特有的。DApp函数,如ContractDataContractFormLoadingContainer ,有助于连接我们的账户,轻松从智能合约中读取数据,并将数据写入区块链。

在下一节中,我们将在React应用程序中利用上述两个模块和Drizzle核心库构建一个DApp。

Drizzle如何与React集成

在我们的Drizzle应用程序中,我们使用Web3提供者连接到以太坊区块链。然后,使用配置文件,我们配置应用程序,使其与我们打算连接的智能合约互动。

Drizzle设置并管理一个内部状态,存储从智能合约内的函数或表达式返回的数据。Drizzle管理这个状态并使其保持最新。然后,通过React和drizzle-react,我们在状态变化时更新/渲染用户界面,使用户界面与智能合约的状态保持同步。

Drizzle使用React的Context API的概念来实现通过整个应用程序的组件树向下传递数据。这样一来,我们的应用程序的上下文就可以提供给我们应用程序的每个工作部分。

通过Drizzle,我们可以设置并整合在本地开发环境(本地机器)上编写的智能合约到我们的前端,或者通过其公共地址和JSON接口导入任何智能合约到我们的前端。在本地开发过程中,运行compile ,和migrate 基于Truffle的命令,构建和部署智能合约,然后为我们提供build/contracts 文件夹,其中包含要消费的JSON接口。

在本教程中,我们将专注于构建DApp的前端,以及如何将其与智能合约或Etherscan.io上的现有智能合约整合。

如何使用 Drizzle 和 React 构建一个前端 DApp

现在,让我们通过使用Truffle框架从头开始启动我们的项目来设置本地开发环境。我们将安装并使用Truffle盒子和ganache-cli工具,它使我们能够建立一个本地区块链,而不需要运行我们自己的实际Ethereum节点的麻烦。

在终端上运行以下命令来安装上面提到的必要工具。然后,创建一个名为drizzle-dapp 的文件夹,改变目录进入其中,并初始化一个前端DApp。

npm install -g truffle
npm install -g ganache-cli
mkdir drizzle-react-tutorial
truffle unbox drizzle
ganache-cli -b 3

命令truffle unbox drizzle ,创建一个完整的代码库,包含构建我们项目所需的所有模板代码。我们将专注于/app 文件夹,因为这是前端将被放置的地方。

Boilerplate Codebase

上述命令还在我们的本地机器上全局安装了ganache-cli。ganache-cli -b 3 命令设置了一个模拟现实中的区块链,以建立我们的前端和智能合约之间的DApp账户集成。

在React中初始化Drizzle和DrizzleStore

接下来,让我们在/app/src/index.js 文件中为我们的DApp导入并初始化Drizzle。

import { Drizzle, generateStore } from "drizzle";
import { DrizzleContext } from "drizzle-react";

import SimpleStorage from "./../build/contracts/SimpleStorage.json";

const options = { contracts: [SimpleStorage] };
const drizzleStore = generateStore(options);
const drizzle = new Drizzle(options, drizzleStore);

ReactDOM.render(
  <DrizzleContext.Provider drizzle={drizzle}>
      <App />
  </DrizzleContext.Provider>,
document.getElementById("root"));

在上面的代码中,我们导入了drizzledrizzle-react 上暴露的功能,并导入了由truffle unbox drizzle 命令提供的启动代码中提供的样本合约。

另外,通过上述代码,我们初始化了一个商店,drizzleStore ,和一个drizzle 对象。

接下来,让我们编辑和更新/app/src/App.js 文件。

import { DrizzleContext } from "@drizzle/react-plugin";
import { Drizzle } from "@drizzle/store";
import drizzleOptions from "./drizzleOptions";
import MyComponent from "./MyComponent";
import "./App.css";

const drizzle = new Drizzle(drizzleOptions);
const App = () => {
  return (
    <DrizzleContext.Provider drizzle={drizzle}>
      <DrizzleContext.Consumer>
        {drizzleContext => {
          const { drizzle, drizzleState, initialized } = drizzleContext;
          if (!initialized) {
            return "Loading..."
          }
          return (
            <MyComponent drizzle={drizzle} drizzleState={drizzleState} />
          )
        }}
      </DrizzleContext.Consumer>
    </DrizzleContext.Provider>
  );
}
export default App;

从上面的代码来看,Drizzle Context Provider在之前的对象之外还提供了一个额外的对象,即initialised 状态。这告诉我们drizzle何时被初始化并连接到web3提供者。

一旦该状态(initialised )可用或完全连接,我们就把它传递给我们的自定义组件(MyComponent )。

在其他组件中消耗DrizzleContext

现在,让我们打开MyComponent 组件所在的/app/src/MyComponent.js 文件。在这里,我们将消费所有提供的道具,并通过DrizzleContext 对象传递。

import { newContextComponents } from "@drizzle/react-components";
...
const { AccountData, ContractData, ContractForm } = newContextComponents;

export default ({ drizzle, drizzleState }) => {
  return (
    <div className="App">
      <div className="section">
        <h2>Active Account</h2>
        <AccountData
          drizzle={drizzle}
          drizzleState={drizzleState}
          accountIndex={0}
          units="ether"
          precision={3}
        />
      </div>
      <div className="section">
        <h2>SimpleStorage</h2>
        <p>
          This shows a simple ContractData component with no arguments, along with a form to set its value.
        </p>
        <p>
          <strong>Stored Value: </strong>
          <ContractData
            drizzle={drizzle}
            drizzleState={drizzleState}
            contract="SimpleStorage"
            method="storedData"
          />
        </p>
        <ContractForm drizzle={drizzle} contract="SimpleStorage" method="set" />
      </div>
    </div>  
  )
}

在上面的代码中,我们只是将DApp的账户与Drizzle整合,以管理账户数据。这也适用于ContractData 对象。顾名思义,这是Drizzle和样本合同之间的数据交互,SimpleStorage.sol

CacheCallCacheSend 函数

现在我们已经在前端设置了Drizzle,让我们使用cacheCallcacheSend 函数对智能合约进行调用,这些函数作为接口提供给drizzle 。这些函数还可以访问drizzleStore ,将智能合约的响应存储在商店中。

接下来,让我们定义一个函数来发送合约数据并将响应存储在DApp的状态中。

...
export default ({ drizzle, drizzleState }) => {
  ...
  const fetchData = () => {
    const state = drizzle.store.getState();
    const key = drizzle.contracts.SimpleStorage.methods.storedData.cacheCall();

    return state.contracts.SimpleStorage.methods.storedData[key].value;
  }
  ....
}
...

上面的代码片段只是使用cacheCall 方法调用智能合约,SimpleStorage 。这个调用返回的响应数据将被存储在drizzleStore ,以及一个用于从drizzleStore 访问这些数据的key

然后,使用drizzleStore 上的key ,上述函数返回智能合约在被调用到用户界面时提供的value 。这样,我们就可以轻松地调用我们的智能合约,并将响应与UI同步。

接下来让我们定义另一个函数来发送一个交易,并将响应存储在我们的商店中。

...
export default ({ drizzle, drizzleState }) => {
  ...
  cnnst state = drizzle.store.getState();
  const id = drizzle.contracts.SimpleStorage.methods.set.cacheSend(
    3,
    { from: Addresse }
  );

  if (state.transactionStack[id]) {
    const transactionHash = state.transactionStack[id];
    return state.transactions[transactionHash].status;
  }
  ...
}
...

上面的代码片段检索了应用程序的状态,然后初始化一个交易,同时为其提供gasfrom 选项。from 代表进行交易的address 。调用cacheSend 方法返回一个id ,这个id 被用来访问DApp的状态上的事务的状态。

现在我们已经将DApp的前端连接到了智能合约上。在终端上,运行以下代码来编译和迁移智能合约。

truffle compile # compiles all the smart contract within the /contracts folder
truffle migrate # deploys the smart contract on the ganache-cli blockchain

现在我们的智能合约和应用程序的前端都准备好了。我们应该能够在输入框中输入一个值并进行交易,然后我们的智能合约的状态将立即更新,同时也会自动更新UI。ContractForm 组件为我们提供了这个输入和表格,以便与智能合约进行互动。

总结

在本教程中,我们介绍了Drizzle作为Truffle套件的一个框架,它使我们的DApp与我们的智能合约的状态同步变得容易。然后,我们探讨了三种可以在DApp中安装和使用Drizzle的方法。我们还介绍了如何在我们的应用程序中设置Drizzzle Context。

Drizzle有助于减少启动DApp项目所需的模板数量。对于下一步,我们可以扩展我们的DApp来构建任何东西,从游戏到购物清单或博客平台,都在区块链平台上。

你可以通过建立更多的组件来扩展本教程中使用的代码,为你想在DApp中加入的功能进行调用或发送交易。然后,扩展智能合约来处理这些功能。本教程中使用的代码可以在GitHub上找到。