**This post assumes base knowledge of blockchain technology and Solidity contracts.
Giant Machines recently developed a DApp (decentralized app) for the Ethereum blockchain, and in the spirit of helping other developers and supporting Truffle, we are sharing some internal notes and comments on our experience with Drizzle. This post addresses the documentation gaps and issues we ran into when initializing Truffle’s new(ish) state management library, Drizzle.
Tools We Used
For our DApp we used React on the front end, Drizzle for state management, and MetaMask as the web3 provider. For our dev environment we used Truffle Develop to create a local blockchain and deploy contracts via the command line. Everything here applies to Drizzle v1.1.0, Drizzle-React v1.1.1, and React v15.4.2.
Initializing Drizzle
Drizzle uses WebSockets and web3, and works on top of Redux with additional methods like cacheCall
and cacheSend
to sync up the store and contract. We saved time by not having to instantiate a web3 connection when making contract calls or polling for changes made to the contract.
In our experience, the Drizzle docs do not reflect what is required to run Drizzle out of the box. The drizzleOptions
object is inflexible and must be configured in a fairly specific way for Drizzle to start. In fact, the drizzleOptions
default did not instantiate Drizzle for us. The drizzleOptions
object must include four properties: web3
, contracts
, polls
, and events
.
Ours looked like this after some trial and error:
drizzleOptions = {
web3: {
block: false,
fallback: {
type: ‘ws’,
url: ‘ws://127.0.0.1:9545’,
},
},
contracts: [
ContractName,
],
polls: {
accounts: IntervalInMilliseconds,
},
events: {},
};
web3.fallback
provides atype
andurl
for the web3 connection if a provider, such as MetaMask, is not availableweb3.fallback.type
only acceptsws
as its valueweb3.fallback.url
must havews
in the protocol identifier instead ofhttp
polls
andevents
should be present as empty objects even if they are not neededpolls
indicates how often Drizzle will ping the blockchain for changes in state- By default,
polls
is{ blocks: 3000 }
, which will poll every 3 seconds, but we found that Drizzle only triggered a re-render with thepolls
set as{ accounts: 3000 }
To connect to Drizzle, wrap the main application component with the DrizzleProvider
from the drizzle-react library and pass drizzleOptions
through the options prop. DrizzleProvider
will generate its own store, but we recommend creating custom actions and reducers on top of what the drizzle library provides. The Drizzle Truffle Box provides an example of how to generate the store with custom reducers.
Drizzle’s React Components
Drizzle has a few of its own React components through the drizzle-react-components library. The LoadingContainer
component from Drizzle wraps the app just below DrizzleProvider
to create a loading page while Drizzle connects to web3. The LoadingContainer
was useful, but the ContractForm
, ContractData
, and AccountData
components were not flexible enough for practical use. We did, however, use these other components for reference on how to use cacheCall
and cacheSend
.
In the Application
The main application component has this structure:
ReactDOM.render(
(
<DrizzleProvider options={drizzleOptions} store={store}
<LoadingContainer>
<BrowserRouter>
<App />
</BrowserRouter>
</LoadingContainer>
</DrizzleProvider>
),
document.getElementById('root'),
);
The Drizzle state and contract instances are accessible through React’s Context API within the App
component. To enable context
where the contract is needed, pass context
as an argument through the constructor()
of a component:
constructor(props, context) {
super(props);
this.drizzleState = context.drizzle;
this.contractInstance = context.drizzle.contracts.SimpleStorage;
}
To add Drizzle to the context
, add the following code to the component, like you did with propTypes
:
ComponentName.contextTypes = {
drizzle: PropTypes.object,
};
The Drizzle state was added to the main application component, and the objects that contained contract methods, web3, and events were passed down separately.
The contractInstance
is required to make calls to the backend and can be passed through props. See the Drizzle docs for how cacheCall
and cacheSend
work with the contract and Drizzle store. They are asynchronous and do not return a promise. Calls can still be made through web3’s call
and send
methods, and these should be used when the result of a promise is required.
A benefit of using Drizzle is that it provides access to a transaction’s status. Pending transactions may take a while to complete, and the transactions
object in the Drizzle state is only updated when cacheSend
is used. This allows the developers to craft a more elegant front-end experience.
Takeaways
It was difficult getting started with Drizzle. If you plan to use any of the Truffle libraries, we highly recommend checking out Truffle boxes before getting started. The Drizzle box will greatly accelerate your configuration of Drizzle.
We’re excited to see more from Truffle! 🙂