Giant Machines LogoGiant Machines Logo
Giant Insights

Ethereum State Management with Drizzle

**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:

-- CODE language-js --
drizzleOptions = {
 web3: {
   block: false,
   fallback: {
     type: ‘ws’,
     url: ‘ws://127.0.0.1:9545’,
   },
 },
 contracts: [
   ContractName,
 ],
 polls: {
   accounts: IntervalInMilliseconds,
 },
 events: {},
};

  • web3.fallback provides a type and url for the web3 connection if a provider, such as MetaMask, is not available
  • web3.fallback.type only accepts ws as its value
  • web3.fallback.url must have ws in the protocol identifier instead of http
  • polls and events should be present as empty objects even if they are not needed
  • polls 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 the polls set as { accounts: 3000 }

To connect to Drizzle, wrap the main application component with the DrizzleProvider from the drizzle-react library and pass drizzleOptionsthrough 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:

-- CODE language-js --
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:

-- CODE language-js --
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:

-- CODE language-js --
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 calland 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 transactionsobject 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! :)

Images

About the Author

Other stories