No more worrying about syncing chain state?
The package is part of Truffle’s suite of tools for developing based front end dapps (decentralised applications). Drizzle aims to solve a state oriented problem; the problem of keeping chain data in sync with your dapp state, and therefore your UI up to date for the end user.
Up until recently developers had to figure out the best approach to sync on-chain activity — contract state, events and transactions — to their dapps via vanilla web3. With the Drizzle package this added consideration is no longer necessary. Drizzle subscribes to new block headers and listens to changes to contract state — contracts that you specifically give Drizzle to listen to. State changes are then persisted automatically with a .
As such, Drizzle works particularly well with React. This article aims to get you up to speed with Drizzle; we will install the Drizzle exploring the project’s capabilities in its current incarnation, as well as out-of-the-box components Drizzle developers have provided us.
Drizzle is a part of the , so some background general knowledge of the suite will be beneficial in following this article. Read my introductory article to understand the dapp development pipeline in relation to the Truffle suite:
The Drizzle Truffle Box
The fastest way to get started with Drizzle is by downloading the Drizzle Truffle Box, a package consisting of a environment combined with, and , giving us access to the full set of Drizzle capabilities within a bootstrapped React app.
Do you need to use React in order to use Drizzle? No — and this is why the Drizzle experience has been broken down into 3 packages, giving developers the option to integrate it into any front end framework they happen to be using.
Let’s quickly run down the purpose of these 3 packages:
drizzle: The core functionality of hosting a “reactive datastore” for web3 and smart contracts. Reactive datastore meaning a Redux that automatically updates when changes are made to your smart contract state. Any Javascript application that has adopted (or plans to adopt) a Redux state container can go ahead and require drizzle as a dependency.drizzle-react: Abstracts the core Drizzle functionality into usable React components. Drizzle takes advantage of React’s for easier integration through your component tree. More on Context next.drizzle-react-components: Not a requirement to get Drizzle to work, but a set of useful UI components that may come in handy during development, currently consisting of , and components.
At this point it is worth taking a quick detour on Context in React to understand how drizzle-react expects us to integrate the drizzle object into our projects. Let’s do that next.
Quick React Context explanation
React’s Context API, (React 16.3 and up) allows us to pass objects down a component tree without embedding them as props throughout the entire component tree. Instead, we wrap that tree with a Context component, making context objects accessible throughout that hierarchy.
Imagine a scenario where we are passing a single string value down 2 or more components. Just passing one value through a component tree is a tedious job. Now, let’s see how a Context Provider can solve this:
const ThemeContext = React.createContext('light');
class App extends React.Component
}
function Toolbar(props)
//Children of your Context provider now have access to provider value
class ThemedButton extends React.Component />;
}
}
First and foremost, a context object is defined with a default value: light. This value can be expanded to an object, array, or any valid type that you require. For example:
const NameOfContext = React.createContext();
A special Provider subcomponent of our context object can then be included in our component tree, as well as a value overwriting the default context value we defined above:
<NameOfContext.Provider value=">
<ComponentTree />
</NameOfContext.Provider>
Now, anywhere in our component tree, we can refer to the context we need (as there may be many contexts embedded in our hierarchy) via the static contextType object, and access the context value like so:
class DeepTreeComponent extends React.Component />;
}
}
The official React docs provide a more detailed explanation of Context as well as alternatives to context when a better solution can be utilised. Check out that page .
Context applied to Drizzle
Now, how is this knowledge of Context applied to Drizzle? Well, a drizzle object firstly needs to be initialised within our root component (or the top-most layer you wish drizzle to be accessible to). From here it would be nice if our entire app had access to the drizzle object — that’s where a Context comes into play:
...
const drizzle = new Drizzle(options, drizzleStore);
ReactDOM.render(
<DrizzleContext.Provider drizzle=>
<App />
</DrizzleContext.Provider>,
document.getElementById('root'));
We now know what the Drizzle box consists of and how we can use context to make Drizzle accessible in our React dapp. Let’s continue our talk by installing the Drizzle Truffle box.
The Drizzle Truffle Box
Intsallation
Let’s move onto installing drizzle from the Drizzle box. Run the following commands to do so:
#install truffle and ganache cli if you have not done so
npm install -g truffle
npm install -g ganache-cli
#unpack the drizzle truffle box
truffle unbox drizzle
#change ganache recommended block time:
ganache-cli -b 3
Why have we changed to a 3 second block time? Because we want to mimic more realistic to dapp communication. Ganache by default mines blocks instantly; any loading indicators or transaction pending indicators will just resolve to a flash in our UX. We don’t want the full 15 second block time, that takes too long, but we do want to be able to test all the components we are developing. 2–3 seconds is plenty enough for this.
As you can see, the Ganache CLI -b option has been called here to change the configuration directly from the Terminal. For more info on ganache-cli, observe the full command list .
Importing Your Contracts
To start using Drizzle we need smart contracts to interact with. There are two methods we can deploy to load smart contracts into our dapp:
- By importing your migrated contract JSON interfaces. In Truffle, running
truffle migrate(the process of deploying your smart contracts from/contractsto a bitcoin) will also generate an additionalbuild/contracts/folder with JSON interfaces of your contracts. These are the files we need to import. - By adding contracts dynamically via their public address and JSON interface.
Note: Provided an owner has verified their contract address on , you can go ahead and copy JSON interfaces of said contract, theoretically allowing us to experiment with any smart contract deployed on a bitcoin hosted on the platform.
Utilising Method 1, we can import contracts and initialise drizzle like so, within index.js.
index.js:
import React, from 'react';
//import drizzle dependencies
import from "drizzle";
import from "drizzle-react";
//import contracts
import SimpleStorage from './../build/contracts/SimpleStorage.json';
import TutorialToken from './../build/contracts/TutorialToken.json';
//define drizzle options. Include contracts here.
const options = ;
//initialise drizzle with options
const drizzleStore = generateStore(options);
//initialise drizzle object, passing options and
const drizzle = new Drizzle(options, drizzleStore);
//include drizzle Context wrapping <App />
ReactDOM.render(
<DrizzleContext.Provider drizzle=>
<App />
</DrizzleContext.Provider>,
document.getElementById('root'));
Drizzle is now initialised at the top layer of your dapp, whereby every component will now have access to Drizzle’s Context object.
Now let’s take a step down into <App />. What the Drizzle Context Provider gives us are 3 objects; namely drizzle, drizzleStore and initialised, thus giving us access to drizzle functionality, drizzle state and whether drizzle is ready to go respectively. “Ready to go” here meaning drizzle is initialised and connected to a web3 provider.
Let’s see what accessing these objects looks like within <App />.
App.js:
import from './MyDrizzleApp';
import from "drizzle-react";
export const App = () => (
//DrizzleContext Consumer gives us access to our drizzle objects.<DrizzleContext.Consumer>
= drizzleContext;
//return a loading UI if drizzle is not yet initialised
if(!initialized)//pass drizzle down as props into a subcomponent
<MyDrizzleApp
drizzle=
drizzleState= />
}}
</DrizzleContext.Consumer>
)
export default App;
Notice how drizzleStore has now changed to drizzleState inside the Context Consumer.
The above demonstrates how we can access drizzle from <DrizzleContext.Consumer>. A loading UI is returned in the event drizzle has not yet initialised.
It is most likely the case that your dapp will not be functional without drizzle initialised, therefore I recommend a fullscreen pre-loader with placeholder shadow animations where necessary.
Note: This <MyDrizzleApp /> example was taken from the official Drizzle documentation. It is amusing how the drizzle Context allows access to drizzle anywhere inside the component tree, the first usage example of which immediately resorts to props. But this at least does highlight our options for passing drizzle around components.
Let’s finally retrieve the drizzle props within <MyDrizzleApp />:
MyDrizzleApp.js:
import React from "react";
export default class MyDrizzleApp extends React.Component = this.props;
}
render()
}
componentDidMount is a preferred method to call contracts and prepare component data derived from web3. Now we have drizzle and drizzleState at hand, let’s explore how to get and set data from smart contracts on the , and how to initiate transactions. This is done with 2 methods in drizzle, cacheCall() and cacheSend().
Interacting with Contracts
and are two methods drizzle provide that not only call smart contract methods and fetch data, but also that response data in drizzleState. Thereafter, that data is kept synchronised with the .
Let’s briefly look at 2 examples of these methods.
cacheCall() sends contract data and stores results in state
Calling cacheCall() will call a smart contract method and the returned data in drizzleState. A key to access this data is also provided upon resolving a cacheCall(), namely the dataKey. Let’s assume drizzle is initialised within MyDrizzleApp, and call a contract method:
const getStoredData = () =>
It is important to keep in mind that this call will continue to synchronise our data with the . If we simply want to get data without storing it in drizzleState, and therefore not synchronise it, we still have access to vanilla web3 methods and properties within drizzle:
drizzle.contracts.SimpleStorage.methods.storedData().call();
Where cacheCall() allows contract interaction, cacheSend() allows us to call and synchronise contract transactions. Let’s look at this next.
cacheSend() sends a transaction and stores results in state
Calling cacheSend() will initiate a transaction. Passing options into this method allows us to supply the standard from, gas and gasPrice of a transaction. Drizzle provides a stackId key, used to access the transaction status and other data in drizzleState.
Let’s look at how a transaction can be called and retrieved from state using cacheSend():
const sendTransaction = () => );
//using stackId, access the transaction hash and status within drizzleState.
if(state.transactionStack[stackId])
}
Like cacheCall(), we also have access to web3 methods in the event that we do not wish this transaction to be synced to the :
drizzle.contracts.SimpleStorage.methods.set(2).send()
Detailed documentation on contract interaction can be found in the official Truffle docs.
Having an existing Redux store
Now, you may already have a redux initialised before introducing Drizzle to your dapp. This is no problem; Drizzle lays out detailed documentation on how to run a drizzleStore inline with your existing , as well as how to combine the drizzleStore into your existing . The preferred method will be dependent on your dapp requirements, but I would lean towards unifying state into one . The full documentation on this subject can be found .
Where to take Drizzle from here
We have now visited how to integrate Drizzle into your dapp using Context, as well as how to call contract methods and send transactions. This can be done with web3, or via drizzle’s cacheCall() and cacheSend() methods, that automatically results in state and keep data synchronised.
Of course, this is not all Drizzle has to offer — read the documentation in full (starting with the ) to familiarise yourself with Drizzle in its entirety. In particular, take note of the structure and drizzle to get a full picture of its capabilities.
My thoughts on Drizzle
Drizzle aims to solve the critical function of keeping your dapps in sync with the network (), and does so in a way whereby developers do not need to think about the inner workings of the package. Drizzle is developer friendly; it allows us to focus more on UX behaviour without worrying how to sync true data from the ; this is done behind the scenes and supplied in your drizzleStore. This is a huge timesaver, trusted that Drizzle is reliable.
drizzle-react-components is still in its early stages with only 3 components currently available from the package; I am confident the offering will grow once more use cases are developed and adopted into the package; time will fix this. However, the component is very useful, providing you a form on the fly to interact with your contracts . This is the main benefit of the package so far, and is great for testing in your front end.
And naturally, Drizzle is a welcome addition to the Truffle suite that is able to be integrated into your project without any changes to your existing Truffle configuration. Overall Drizzle is a strong addition to the Truffle suite.
Published at Mon, 14 Jan 2019 13:15:50 +0000