Connecting to MetaMask +React.js + Custom Hook + State Management

0
48
Photo by DrawKit Illustrations on Unsplash

Connecting your dApp to MetaMask is an important step in getting things going with the endless possibilities your app may usher into Web3. It is rather simple to create a custom hook which can be implemented to transact with MetaMask throughout your entire app.

We want to achieve 3 things for this project.

  1. Connect MetaMask to a React.js Application
  2. Create a Custom Hook to keep track of the state of your application working with MetaMask
  3. Wrap a Web3 provider around the App for future transactions to the ETH chain of your choice

The end result will look something like this:

We are also going to include an option to disconnect your app from MetaMask if this is what the user is wanting to do.

Let’s go!

Let’s first start by creating a new app with React. I’m using npx create-react-app . I am also using VS Code for this tutorial as well just to note.

npx create-react-app react-metamask-medium && cd react-metamask && code .

Ok, good to go! You should have a simple react application, and if you open up App.js it should look like this:

Let’s do a little cleaning and remove everything we don’t need. I am going to remove everything in between <header></header> and place my new content in there. I am going to be using the existing CSS to center and drop the new content:

Now let’s add a few package to drop in some buttons for the content. I am also going to add a MetaMask logo and hand wave svg, here is the link to download if you’re interested: metamask.svg. hand.svg

yarn add react-bootstrap bootstrap@5.1.3

Let’s add import ‘bootstrap/dist/css/bootstrap.min.css’ to our index.js file and also remove some extra code. Your index.js should look like this:

Now let’s add the buttons to the app so we can connect to MetaMask.

Now we need to create a Custom Hook that we can use to call connect and disconnect on these buttons. This custom hook will also keep track of the state of our app and dish out any data we need such as account info or balance.

We should create a folder called hooks and drop in useMetaMask.js for the custom hook, so our folder structure looks like this: src/hooks/useMetaMask.js

To keep track of the State of this hook throughout the entire app’s lifecycle, we’ll have to utilize React’s createContext

This is a bit much to break down, but for a simple boiler plate that we will fill, please see the following code:

For this component we are going to need the following from React, useState, useEffect, useMemo, and useCallback

We are also going to need to use @web3-react/core’s useWeb3React hook as well as create a new component called injected. This injected component will utilize web3-react/injected-connector to connect supported chain’s to the app and MetaMask.

Let’s run the following:

yarn add @web3-react/injected-connector @web3-react/core

Next let’s begin to fill out our new useMetaMask hook to work with out app. To do this we will drop all our code inside the MetaMaskProvider component.

First up we will want to add the useWeb3React hook to gather some important resources for connecting with MetaMask.

const { activate, account, library, connector, active, deactivate } = useWeb3React()

I also start to create some specific states I want to keep track of like isActive and isLoading.

isLoading will be useful to tell when the useMetaMask hook is loading to read its connection with MetaMask. isActive will be useful to tell if MetaMask is currently connected to the app with the proper chain i am allowing inside the app.

const [isActive, setIsActive] = useState(false)

const [isLoading, setIsLoading] = useState(true)

To see the full code on this custom hook please click here

Next I should create my injected component which will be used to connect MetaMask to specific the specific Chains I am wanting to use with my app.

I will create a folder called src/components/wallet/injected.js to drop the injected component file into. The code is simple:

import { InjectedConnector } from ‘@web3-react/injected-connector’

export const injected = new InjectedConnector({ supportedChainIds: [1, 42, 1337] })

The supportedChainIds will help to make sure MetaMask is connected to the proper chains my app is using, otherwise it won’t show active in our custom hook.

For more support Chain IDs please see https://chainlist.org/

1 = Ethereum Mainnet
42 = Kovan Testnet — Which I will use to connect in a later article using Web3 and Infura which will come in handing is making simple simple transactions to test out my app

1337 = Local Host chain. For this I used Ganache to create a local chain and connect to my MetaMask wallet.

Now back to our useMetaMask hook.

We want to use useEffect with no dependency which will run once when the hook is initialized. Inside of this useEffect hook will will drop on a connect() function to initialize the connection to the App and MetaMask when the app is first ran:

These functions when called will help connect and disconnect the wallet to the app. I am using them as a useCallback function because I don’t want them to re-render more than needed in the app, only when they are called.

Next let’s create a handleIsActive function to check if MetaMask is currently connected to our app. I am going to use a useCallback for this and drop in active property from our useWeb3React hook as a dependency to update our hook when MetaMask is connected and disconnected from our app. This will usually be because the user switch accounts on MetaMask for a chain that was not connected to our app:

I also created a useEffect hook that will depend on handleIsActive and run this function only when active has changed inside the handleIsActive callback. This will update our app anytime it becomes active true or false. Disconnecting MetaMask from our app will also cause active to be false.

Last to make sure that the useMetaMask custom hook updates the rest of our app accordingly if any of its dependencies change, we will use useMemo to change the props of our hook accordingly. We do this so the rest of the app can tell if isActive or isLoading is updated. Also this will give access to our connect and disconnect functions, plus our account. They will only reevaluate when our needed dependencies change such as isActive and isLoading:

Cool now good to go. To checkout out the full source code of this custom hook click here

Last step is to use the Web3ReactProvider around our existing app and also use our MetaMaskProvider as well to wrap the app so we can have the state of our custom hook existing at all times.

We need to lastly add our last dependency:

yarn add web3

Once we wrap the app in index.js and use everything it should look like this:

The reason for wrapping out app is the following Web3ReactProvider is what our useWeb3React hook depends on and it also paves the way for using Web3 and transacting with our app.

Using the MetaMaskProvider around our <App /> gives us the ability to keep the state of our custom hook throughout the entire app.

Next we can pop back to our App.js and use our Custom Hook we created.

Drop in the following to our App:

const { connect, disconnect, isActive, account } = useMetaMask()

As well we should put the following next to our Connected Account:

{ isActive ? account : ‘’ }

This is going to tell our app if the account is connected, then show the account info. If not show a blank string.

We should also connect our buttons to connect and disconnect functions from our useMetaMask hook.

The end result will look like the following:

This is what our app will look like when it runs:

Right on! Well thanks for coding along with me! Please check out the full source code here at: https://github.com/blakewood84/react-metamask-medium

Please feel free to reach out to me on LinkedIn anytime if you’re interested in projects or talking code! https://www.linkedin.com/in/blakewoodjr/

Thanks a lot! Bless

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also Read


Connecting to MetaMask +React.js + Custom Hook + State Management was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.