Published on

Drizzle Returning 0x0

Authors

Today we started adding a UI to our dApp. The drizzle framework seemed ideally suited for this as we use React for our front ends and the truffle suite for our contract dev.

We started by completing the official tutorial and everything worked perfectly with a few minor issues that had to be fixed. The broken piece of code from the tutorial was:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
...
ReactDOM.render(<App drizzle={drizzle} />, document.getElementById("root"));
registerServiceWorker();

We changed this to the following to fix this:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
// import registerServiceWorker from "./registerServiceWorker";
import  * as serviceWorker from './serviceWorker';
...
ReactDOM.render(<App drizzle={drizzle} />, document.getElementById("root"));
serviceWorker.unregister();

Armed with this knowledge we started trying to apply this to our smart contracts. We started simply by putting everything into one component (with the aim of breaking that component up into smaller pieces later). We placed this all in App.js component which looked like the following:

class App extends Component {
  state = { loading: true, drizzleState: null }

  componentDidMount() {
    const { drizzle } = this.props
    const contract = drizzle.contracts.MyStringStore
    console.log(`contract: ${contract}`)

    this.unsubscribe = drizzle.store.subscribe(() => {
      const drizzleState = drizzle.store.getState()

      if (drizzleState.drizzleStatus.initialized) {
        this.setState({ loading: false, drizzleState })
      }
    })
  }

  componentWillUnmount() {
    this.unsubscribe()
  }

  render() {
    if (this.state.loading) return 'Loading Drizzle...'
    return <div className="App">Drizzle is ready</div>
  }
}

Which output: contract: undefined. We thought this might be an issue with Drizzle not being ready so we tried to move this into the if statement: if (drizzleState.drizzleStatus.initialized):

...
const { drizzle } = this.props;
    this.unsubscribe = drizzle.store.subscribe(() => {
        ...
        if (drizzleState.drizzleStatus.initialized) {
            // our contract calls were moved to here
            const contract = drizzle.contracts.MyStringStore;
            const dataKey = contract.methods["myString"].cacheCall();
            console.log(`dataKey: ${dataKey}`);

            this.setState({ loading: false, drizzleState });
        }
    ...
}

This output: dataKey: 0x0. We dug around a bit more but in the end decided to compare each file to the tutorial's files. What we found was that this issue was indeed caused by a timing issue and we in fact had to have a parent component that waited for drizzle to load and only once it had loaded would it load the child components and pass drizzle to them. Our final code looked like this for the App.js file:

import React, { Component } from 'react'
import './App.css'
import YourChildComponent from './YourChildComponent'

class App extends Component {
  state = { loading: true, drizzleState: null }

  //the below componentDidMount is boilerplate
  componentDidMount() {
    const { drizzle } = this.props

    this.unsubscribe = drizzle.store.subscribe(() => {
      const drizzleState = drizzle.store.getState()

      if (drizzleState.drizzleStatus.initialized) {
        this.setState({ loading: false, drizzleState })
      }
    })
  }

  //the below componentWillUnmount is boilerplate
  componentWillUnmount() {
    this.unsubscribe()
  }

  // the render method is boilerplate except for the child component/s you load
  // child components either way need to be passed drizzle and drizzleState as props
  render() {
    if (this.state.loading) return 'Loading Drizzle...'
    return (
      <div className="App">
        <YourChildComponent drizzle={this.props.drizzle} drizzleState={this.state.drizzleState} />
      </div>
    )
  }
}

export default App

The key lines in the above are the bit in the render where YourChildComponent is only rendered (and passed drizzle as props) once drizzle is finished loading. The rest of the file is needed but boilerplate code you will always need in your main root component when using drizzle.

The child component is very straight forward and quite boilerplate:

import React from 'react'

class YourChildComponent extends React.Component {
  state = { dataKey: null }

  componentDidMount() {
    const { drizzle } = this.props
    const contract = drizzle.contracts.TheContractYourDAppWillUse

    const dataKey = contract.methods['nameOfMethodYouWantToCall'].cacheCall()

    this.setState({ dataKey })
  }

  render() {
    const { TheContractYourDAppWillUse } = this.props.drizzleState.contracts

    const resultOfMethodCall =
      TheContractYourDAppWillUse.nameOfMethodYouWantToCall[this.state.dataKey]

    return <p>{resultOfMethodCall && resultOfMethodCall.value}</p>
  }
}

export default YourChildComponent

The index.js file is also boilerplate except for the part where you define one or more contracts (notice how the contract name exactly matches the destructured object in the child component render method above):

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'

import { Drizzle, generateStore } from 'drizzle'
import TheContractYourDAppWillUse from './contracts/TheContractYourDAppWillUse.json'

const options = { contracts: [TheContractYourDAppWillUse] }

const drizzleStore = generateStore(options)
const drizzle = new Drizzle(options, drizzleStore)

ReactDOM.render(<App drizzle={drizzle} />, document.getElementById('root'))
serviceWorker.unregister()