Frameworks have made it easier and faster to bootstrap and configure web projects by providing the initial code/setup and tools needed to start building any frontend application. The world of blockchain and DApp development is no exception.
In this tutorial, we’ll show you how to use the Drizzle framework to build frontend applications on Ethereum. We’ll examine a practical example in which we’ll use Drizzle alongside React to build a DApp.
Here’s what we’ll cover:
To comfortably understand the concepts we’ll cover in this tutorial, you’ll need basic knowledge of the following:
Drizzle as a framework based on the Truffle Suite. It’s a JavaScript library that provides interfaces for Web3, account and contract instantiation, and additional contract functionality and helps with wiring up the necessary synchronizations.
Drizzle is the main library. It contains the core logic of Drizzle and integrates manually with your application.
Drizzle can be installed as an npm package, meaning you’d need Node.js installed on your local machine to use the Node.js commands through the terminal to install Drizzle.
Alternatively, you can use Truffle Boxes to handle the installation.
Drizzle, the core library, offers a reactive store for frontend applications in Web3 and smart contracts. The reactive store is fashioned in likeness to Redux store, meaning it automatically updates when it detects updates on the state of the smart contract or that of the UI. We can incorporate Drizzle into any JavaScript-based project
There are two main modules that can be installed alongside Drizzle. These modules provide interfaces that make building DApps easier.
DrizzleProvider
component and drizzleConnect
helper method to make it easier to connect Drizzle with your React app. These are higher-order Provider
components that help wrap the other components within our application and pass the state of Drizzle down to themContractData
, ContractForm
, and LoadingContainer
help to connect our account, easily read data from smart contracts, and write data to the blockchainIn the next section, we’ll build a DApp leveraging the two aforementioned modules together with the Drizzle core library within a React application.
Within our Drizzle application, we connect to the Ethereum blockchain using a Web3 provider. Then, using a configuration file, we configure the application to interact with the smart contract we intend for it to connect to.
Drizzle sets up and manages an internal state that stores the data returned from functions or expressions within the smart contract. Drizzle manages this state and keeps it up to date. Then, through React and drizzle-react, we update/rerender the UI on state changes, keeping the UI in sync with the smart contract’s state.
Drizzle uses the concept of the React’s Context API to implement passing of data down through the component tree of the whole application. This way, the context of our application is made available to every working part of our application.
With Drizzle, we can set up and integrate smart contracts that were wrote on the local development environment (local machine) into our frontend or import any smart contract through its public address and JSON interface into our frontend. Running the compile
, and migrate
Truffle-based commands during local development builds and deploys the smart contracts, then provides us with the build/contracts
folder that contains the JSON interfaces to consume.
For this tutorial, we’ll focus on building the frontend of a DApp and how to integrate it with a smart contract or an existing smart contract on Etherscan.io.
Now let’s set up our local development environment by bootstrapping our project from scratch using the Truffle framework. We’ll install and use the Truffle box alongside the ganache-cli tool, which enables us to set up a local blockchain without the hassle of running our own actual Ethereum node.
Run the following commands on the terminal to install the necessary tools mentioned above. Then, create a folder named drizzle-dapp
, change directory into it, and initialize a frontend DApp.
npm install -g truffle npm install -g ganache-cli mkdir drizzle-react-tutorial truffle unbox drizzle ganache-cli -b 3
The command truffle unbox drizzle
creates a full codebase that contains all the boilerplate code needed to build our project. We’ll focus on the /app
folder because this is where the frontend will be located.
The above command also installs ganache-cli globally on our local machine. The ganache-cli -b 3
command sets a mimic of a realistic blockchain to establish a DApp account integration between our frontend and smart contract.
DrizzleStore
in ReactNext, let’s import and initialize Drizzle for our DApp in the /app/src/index.js
file:
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"));
In the above code, we imported the functionalities exposed on drizzle
and drizzle-react
and imported sample contracts made available from the starter code provided by the truffle unbox drizzle
command.
Also, with the above code, we initialized a store, drizzleStore
, and a drizzle
object.
Next, let’s edit and update the /app/src/App.js
file:
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;
From the above code, the Drizzle Context Provider provides an extra object alongside the previous ones, an initialised
state. This tells us when drizzle is initialized and connected to a web3 provider.
Once the state, initialised
, is available or fully connected, we then pass it down to the our custom component, MyComponent
.
DrizzleContext
in other componentsNow, let’s open the /app/src/MyComponent.js
file where the MyComponent
component is located. This is where we’ll consume all the props provided and passed through the DrizzleContext
object.
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> ) }
In the above code, we’re simply integrating the account of the DApp with Drizzle to manage the account data. This also applies to the ContractData
object. As the name suggests, this is an interaction of data between Drizzle and the sample contract, SimpleStorage.sol
.
CacheCall
and CacheSend
FunctionsNow that we’ve set up Drizzle on the frontend, let’s make calls to the smart contract using the cacheCall
and the cacheSend
functions made available as interfaces on drizzle
. The functions also has access to the drizzleStore
to store response from the smart contract within the store.
Next, let’s define a function to send contract data and store the response in the DApp’s state.
... 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; } .... } ...
The above code snippet simply calls the smart contract, SimpleStorage
, using the the cacheCall
method. This call returns response data that would be stored in the drizzleStore
and a key
for accessing this data from the drizzleStore
.
Then, using the key
on the drizzleStore
, the above function returns the value
made available by the smart contract when it was called to the UI. This way, we can easily call our smart contracts and synchronize the response with the UI.
Next let’s define another function to send a transaction and store the response in our store:
... 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; } ... } ...
The above code snippet retrieves the state of the application, then initialize a transaction while providing it with the gas
and from
options. The from
represents the address
making the transaction. Calling the cacheSend
method returns an id
, and this id
is used to access the state of the transaction on the DApp’s state.
Now we have connected the frontend of our DApp to the smart contract. On the terminal, run the following code to compile and migrate the smart contract:
truffle compile # compiles all the smart contract within the /contracts folder truffle migrate # deploys the smart contract on the ganache-cli blockchain
Now we have our smart contracts and the frontend of the application ready. We should be able to type a value into the input field and make a transaction, and then the state of our smart contract will immediately update as well as the UI, automatically. The ContractForm
component provides us with this input and form to interact with the smart contract.
In this tutorial, we introduced Drizzle as a framework of the Truffle suite, which makes it easy to sync our DApp together with the state of our smart contracts. Then, we explored the three methods through which Drizzle can be installed and used within a DApp. We also covered how to set up Drizzzle Context within our application.
Drizzle helps reduce the amount of boilerplate that is needed to bootstrap a DApp project. For next steps, we can extend our DApp to build anything, from a game to a shopping list or a blog platform, all on the blockchain platform.
You can extend the code used within this tutorial by building more components to make calls or send transactions for the features you want to incorporate within your DApp. Then, extend the smart contract to handle these features. The code used within this tutorial is available on GitHub.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.