• Create your First Ethereum dAPP with Web3 and Vue.js (Part 2)
  • Original by Alt Street
  • Translation from: The Gold Project
  • This article is permalink: github.com/xitu/gold-m…
  • Translator: L9m
  • Proofreader: Allen, Jade
  • Use Web3 and Vue.js to create your first Ethereum dAPP (Part 1)
  • Use Web3 and Vue.js to create your first Ethereum dAPP (Part 2)
  • Use Web3 and Vue.js to create your first Ethereum dAPP (Part 3)

Click here to share this article on LinkedIn

Welcome back to the second part of this great series of tutorials on building our first decentralized application. In Part 2, we will introduce the core concepts of VueJS and VueX and how Web3JS interacts with Metamask.

If you missed the first part, you can find it below, and please follow us on Twitter.

Getting to the point: VueJS

VueJS is a JavaScript framework for building user interfaces. At first glance, it looks like a traditional Mustache template, but Vue has done a lot of work behind it.

<div id= "app" > {{message}} </div> var app = new Vue({el:'#app',
 data: {
 message: 'Hello Vue! '}})Copy the code

This is a very basic structure for Vue applications. The message property in the data object is rendered to an on-screen element with the ID “app”, and the on-screen value is updated in real time as we change the message. You can check it out on this Jsfiddle (with auto running enabled) : jsfiddle.net/tn1mfxwr/2/.

Another important feature of VueJS is the component. Components are small, reusable, and nested pieces of code. Essentially, a Web application is made up of a component tree of smaller components. This will become clearer when we start writing our front-end applications.

This page example is made up of components. A page is made up of three components, two of which have child components.

Integration of states: Vuex

We use Vuex to manage the state of the application. Like Redux, Vuex implements a container with a “single data source” for our application data. Vuex allows us to manipulate and provide data used by our applications in a predictable way.

The way it works is very intuitive. When a component needs data to render, it dispatches an action to get the required data. The API call to fetch data in the Action is asynchronous. Once the data is obtained, the action commits the data to a mutation. Then, the Mutation will alert the state of our store. When the data in the container used by the component changes, it is rerendered.

State management mode of Vuex.

Before we move on…

In the first part, we have generated a Vue application using vue-CLI, and we have installed the required dependencies. If you haven’t done so, check out the link in section 1 above.

If you have completed the items correctly, your catalog should look like this:

Newly generated VUE applications.

Tip: If you want to copy and paste the code snippet from here, please click on your.eslintignoreAdd to file/src/To avoid indenting errors.

You can run the application by typing NPM start in the terminal. First we need to clean up the default Vue application it contains. Note: Although there is only one route, we will use the Vue Router, which we don’t need, but since the tutorial is fairly simple, I think it would be better to keep it. Tip: In the lower right corner of your Atom editor, set the.vue file to HTML syntax (highlighted)

Now deal with the newly generated application:

  • Delete the img tag and style tag in app.vue.
  • deletecomponents/HelloWorld.vue, create two new files named casino-dapp.vue (our main component) and Hello-Metamask.vue (which will contain our Metamask data).
  • In our newhello-metamask.vuePaste the following code into the file, which now shows only the “Hello” text within a P tag.
<template>
 <p>Hello</p>
</template>

<script>
export default {
 name: 'hello-metamask'
}
</script>

<style scoped>

</style>
Copy the code
  • Now we first import the Hello-Metamask component file, load it into the main component casino-app by importing the file, and then reference it as a tag in the template in our vue instance. incasino-dapp.vuePaste this code in:
<template>
 <hello-metamask/>
</template>

<script>
import HelloMetamask from '@/components/hello-metamask'
export default {
 name: 'casino-dapp',
 components: {
 'hello-metamask': HelloMetamask
 }
}
</script>

<style scoped>

</style>
Copy the code
  • Now if you open router/index.js you will see that there is only one route under root, which is still pointing to the HelloWorld.vue component that we removed. We need to point it to our main component casino-app.vue.
import Vue from 'vue'
import Router from 'vue-router'
import CasinoDapp from '@/components/casino-dapp'

Vue.use(Router)

export default new Router({
 routes: [
 {
 path: '/',
 name: 'casino-dapp',
 component: CasinoDapp
 }
 ]
})
Copy the code

About Vue Router: You can add additional paths and bind components to them. When you access the defined path, the corresponding component is rendered and displayed in the router-View tag in the app.vue file.

  • insrcCreate a file namedutilIn this folder create another folder namedconstantsAnd create a folder namednetworks.jsPaste the code below. We use the ID instead of the Ethereum network name display to keep our code clean.
export const NETWORKS = {
 '1': 'Main Net'.'2': 'Deprecated Morden test network'.'3': 'Ropsten test network'.'4': 'Rinkeby test network'.The '42': 'Kovan test network'.'4447': 'Truffle Develop Network'.'5777': 'Ganache Blockchain'
}
Copy the code
  • Last but not least (actually not needed right now) is insrcCreate a file namedstoreNew folder. We will continue this discussion in the next section.

If you execute NPM start in your terminal and access localhost:8000 in your browser, you should see “Hello” appear on the screen. If so, you’re ready to take the next step.

Set up our Vuex container

In this section, we will set up our container (store). Start by creating two files under the store directory (the last part of the previous section) : index.js and state.js; We’ll start with state.js, which is a Blank representation of the data we’re retrieving.

let state = {
 web3: {
 isInjected: false,
 web3Instance: null,
 networkId: null,
 coinbase: null,
 balance: null,
 error: null
 },
 contractInstance: null
}
export default state
Copy the code

Ok, now we need to set index.js. We will import the Vuex library and tell VueJS to use it. We will also import state into our Store file.

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'

Vue.use(Vuex)

export const store = new Vuex.Store({
 strict: true,
 state,
 mutations: {},
 actions: {}
})
Copy the code

The final step is to edit main.js to include our store file:

import Vue from 'vue'
import App from './App'
import router from './router'
import { store } from './store/'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
 el: '#app',
 router,
 store,
 components: { App },
 template: '<App/>'
})
Copy the code

Well done! Because there are a lot of Settings, give yourself a pat on the back. We are now ready to take our Metamask data through the Web3 API and make it useful in our application. It’s time for the real thing!

Get started with Web3 and Metamask

As mentioned earlier, in order for the Vue application to get the data, we need to dispatch an action to perform an asynchronous API call. We’ll use the Promise to chain calls to several methods and extract (encapsulate) the code into the file util/getWeb3.js. Paste the code below, which contains some comments to help you follow. We will parse it under the code block:

import Web3 from 'web3'

/* * 1. Check for injected web3 (mist/metamask) * 2. If metamask/mist create a new web3 instance and pass on result * 3.  Get networkId - Now we can check the user is connected to the right network to use our dApp * 4. Get user account from metamask * 5. Get user balance */

let getWeb3 = new Promise(function (resolve, reject) {
  // Check for injected web3 (mist/metamask)
  var web3js = window.web3
  if (typeofweb3js ! = ='undefined') {
    var web3 = new Web3(web3js.currentProvider)
    resolve({
      injectedWeb3: web3.isConnected(),
      web3 () {
        return web3
      }
    })
  } else {
    // web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545')) GANACHE FALLBACK
    reject(new Error('Unable to connect to Metamask'))
  }
})
  .then(result= > {
    return new Promise(function (resolve, reject) {
      // Retrieve network ID
      result.web3().version.getNetwork((err, networkId) = > {
        if (err) {
          // If we can't find a networkId keep result the same and reject the promise
          reject(new Error('Unable to retrieve network ID'))}else {
          // Assign the networkId property to our result and resolve promise
          result = Object.assign({}, result, {networkId})
          resolve(result)
        }
      })
    })
  })
  .then(result= > {
    return new Promise(function (resolve, reject) {
      // Retrieve coinbase
      result.web3().eth.getCoinbase((err, coinbase) = > {
        if (err) {
          reject(new Error('Unable to retrieve coinbase'))}else {
          result = Object.assign({}, result, { coinbase })
          resolve(result)
        }
      })
    })
  })
  .then(result= > {
    return new Promise(function (resolve, reject) {
      // Retrieve balance for coinbase
      result.web3().eth.getBalance(result.coinbase, (err, balance) => {
        if (err) {
          reject(new Error('Unable to retrieve balance for address: ' + result.coinbase))
        } else {
          result = Object.assign({}, result, { balance })
          resolve(result)
        }
      })
    })
  })

export default getWeb3
Copy the code

The first thing to note is that we have linked our callback methods with Promises. If you are not familiar with Promises, please refer to this link. Next we’ll check to see if the user has Metamask (or Mist) running. The Metamask injects an instance of Web3 itself, so we need to check whether window.web3 (the injected instance) is defined. If not, we will create an instance of Web3 with Metamask as the currentProvider, so that the instance does not depend on the version of the injected object. We pass the newly created instance to the following promise, where we make a few API calls:

  • web3.version.getNetwork()Returns the ID of the network we are connected to.
  • web3.eth.coinbase()Returns the address where our node mines, which should be the selected account when using Metamask.
  • web3.eth.getBalance(<address>)Returns the balance of the address passed in as a parameter.

Remember when we said that the actions in the Vuex container need to make API calls asynchronously? We connect it here and then trigger it from the component. In store/index.js, we would import the getWeb3.js file, call it, commit it to a mutation, and leave it in the container.

Add to your import statement:

import getWeb3 from '.. /util/getWeb3'
Copy the code

Then call getWeb3 in the Action object (inside the store) and commit the result. We will add some console.log to our logic in the hope that the dispatch-action-commit-mutation-statechange process will be clearer and help us understand the steps of the entire execution.

registerWeb3 ({commit}) {
      console.log('registerWeb3 Action being executed')
      getWeb3.then(result => {
        console.log('committing result to registerWeb3Instance mutation')
        commit('registerWeb3Instance', result)
      }).catch(e => {
        console.log('error in action registerWeb3', e)
      })
    }
Copy the code

Now we will create our mutation, which stores the data as state in the container. By accessing the second parameter, we can access the data in our COMMIT to mutation. The following methods are added to the mutations object:

registerWeb3Instance (state, payload) {
 console.log('registerWeb3instance Mutation being executed', payload)
 let result = payload
 let web3Copy = state.web3
 web3Copy.coinbase = result.coinbase
 web3Copy.networkId = result.networkId
 web3Copy.balance = parseInt(result.balance, 10)
 web3Copy.isInjected = result.injectedWeb3
 web3Copy.web3Instance = result.web3
 state.web3 = web3Copy
 }
Copy the code

Great! Now all that’s left to do is to dispatch an action in our component to get the data and present it in our application. To dispatch an action, we’ll use Vue’s lifecycle hook. In our example, we will dispatch the action before it is created. Add the following method under the name attribute in components/casino-dapp.vue:

export default {
  name: 'casino-dapp'.beforeCreate () {
    console.log('registerWeb3 Action dispatched from casino-dapp.vue')
    this.$store.dispatch('registerWeb3')
  },
  components: {
    'hello-metamask': HelloMetamask
  }
}
Copy the code

Very good! Now we will render the data for the Hello-Metamask component, where all the data for our account will be rendered. To get data from a container (store), we need to add a getter method to the evaluated property. We can then use braces to reference the data in the template.

<template>
 <div class='metamask-info'>
   <p>Metamask: {{ web3.isInjected }}</p>
   <p>Network: {{ web3.networkId }}</p>
   <p>Account: {{ web3.coinbase }}</p>
   <p>Balance: {{ web3.balance }}</p>
 </div>
</template>

<script>
export default {
 name: 'hello-metamask',
 computed: {
   web3 () {
     return this.$store.state.web3
     }
   }
}
</script>

<style scoped></style>
Copy the code

That’s great! It should all be done by now. Start the project from your terminal with NPM start and access localhost:8080. Now, we can see the Metamask data. When we open the console, we should see the console.log output, which describes the state management mode in the Vuex section.

Seriously, if you’ve made it this far and everything’s fine, then you’re great! This is by far the most difficult part of the series. In the next section, we’ll learn how to poll for changes in Metamask (e.g., account switching), and in the first section we’ll describe how smart contracts are connected to our application.

Just in case you make a mistake, inThis Github repositoryThe complete code for this part is on the Hello-Metamask branch of

Don’t miss the last part of this series!

If you enjoyed this tutorial, please let us know, and thanks for reading it to the end.

The ETH – 0 x6d31cb338b5590adafec46462a1b095ebdc37d50


Want to finish your idea? We offer crowdfunding for proof-of-concept and development with Ethereum.

  • Alt Street — Blockchain advisor: Blockchain proof-of-concept and token sales… altstreet.io

Diggings translation project is a community for translating quality Internet technical articles from diggings English sharing articles. The content covers the fields of Android, iOS, front end, back end, blockchain, products, design, artificial intelligence and so on. For more high-quality translations, please keep paying attention to The Translation Project, official weibo and zhihu column.