How to Connect a ReactJs DApp to MetaMask

A step-by-step guide on how to use Ether.Js to connect a React DApp to MetaMask

Williams Peter
Coinmonks
Published in
10 min readMar 17, 2023

--

Photo by Joshua Aragon on Unsplash

Introduction

The world of decentralized applications (DApps) is ever-expanding, and the use of blockchain technology is becoming more commonplace. With the emergence of innovative platforms like Ethereum, developers have been able to create robust and secure applications with greater ease than ever before. One of the most popular tools for creating decentralized applications is called React.

React is a JavaScript library used to build user interfaces, and it has been used to create some of the most popular DApps in the world. To ensure that users have the best experience possible, developers must ensure that their React DApp is properly connected to MetaMask, a popular browser extension for accessing Ethereum networks. In this guide, we’ll cover a great deal of information, but let’s begin by acquainting ourselves with the essential terms and technologies that will be referenced.

What is a Decentralized Application (DApp)?

Decentralized Applications (DApps) are applications that run on a distributed network of computers, as opposed to running on a single computer. A DApp can be thought of as a blockchain-enabled application, where all the data and records of the application are stored on the blockchain.

DApps are often open-source and decentralized, meaning that no single entity controls the application or the data stored within it. They offer users full control over the data and records, as no one entity is able to modify or delete them. DApps have the potential to revolutionize the way applications are built and used, as they enable users to interact directly with each other as well as with the application itself.

What is MetaMask?

MetaMask is a browser extension that allows users to securely connect to the Ethereum blockchain. It acts as an intermediary between users and DApps, allowing users to securely access and interact with DApps without having to run a full Ethereum node.

MetaMask also functions as a digital wallet, allowing users to store, send, and receive Ether and other ERC-20 tokens. MetaMask is available for Chrome, Firefox, Brave, and Opera browsers and can also be used on mobile devices via the MetaMask Mobile app.

What is Ether.Js?

Ethers.js is a free and open-source JavaScript library that enables developers to work with the Ethereum blockchain. It is comparable to web3.js, and it is the library that we will be using for this article. It includes JavaScript and TypeScript utility functions, as well as all of the functionality of an Ethereum wallet.

Now that we are familiar with the core technologies that will be utilized in this article, let’s get our hands dirty and build our first DApp. In this example, we will be building a React application that we can connect to MetaMask using Ether.Js. We’ll cover the basics of MetaMask, the necessary steps to connect your DApp to MetaMask, and how to use MetaMask to interact with your DApp.

Step 1: Prerequisites

These are the prerequisites:

  • Having knowledge of HTML, CSS, and JavaScript fundamentals.
  • Familiarity with React.
  • Setting up Material UI (MUI) for styling our application
  • Node and npm or yarn are installed on our machine.
  • Gaining a basic knowledge of how the terminal operates.

To begin, we can utilize Create React App (CRA) to set up our React application and quickly start developing a single-page application in React.

Note: You can use any name of your choice when creating your application

npx create-react-app react-dapp-metamask

The next step would be to navigate to the project directory and start the server when that has been accomplished.

cd react-dapp-metamask

npm start

Project structure: It will look like the following:

Project Structure for a React.Js Application

Step 2: Install Ethers.js

Once we have built our React application, we can install Ethers.js in our project’s folder using the following command:

npm install --save ethers

We can verify that the ethers.js dependency has been installed correctly by taking a look at our package.json file, and it should look something like this in the image below:

ether.js and its recent version in the package.json file

Note: The version in the image above is the most recent version as of the time I wrote this article. Yours might be different.

Step 3: configure Material UI

Now, you can go back to your project terminal, where we will be setting up the Material UI. It is a library of React components that implement Google’s Material Design Specification. To get started, you can run one of the commands below:

Npm

npm install @mui/material @emotion/react @emotion/styled

Yarn

yarn add @mui/material @emotion/react @emotion/styled

Note: In this project, we will just be using the button component from the library. In the next step, you will see how you can import a component from the library and how it can be used. You can learn more about the library from its documentation as it is one of the best UI libraries for React and Next projects.

Step 4: Edit the App.js file

Next, go to the src folder in the root folder of your project, click to open the app.js file, remove the placeholder code there, and replace it with the code below.

const App = () => {
return (
<div className="App-header">
<div className="centerCard">
<div className = "card">
<div className="App">
<WalletCard/>
</div>
</div>
</div>
</div>
)
}

export default App;

Within our src folder, we will now create a new file with the name WalletCard.js. All of our project’s user interfaces and related functionality will be housed in WalletCard.js.

Step 5: Run RAFCE for Boilerplate

RAFCE stands for React-App-Folder-Component-Files-Structure. It is a tool to help developers quickly scaffold out a React boilerplate. You should see something like this in your code editor.

Result from running RAFCE in a code editor for a React Boilerplate

Step 6: Import all packages needed

Next, we will be importing the different packages we need from different sources. You can copy and paste the code below into your WalletCard.js file above the generated boilerplate code.

import React, { useState } from 'react';
import Button from '@mui/material/Button';
import Ethereum from './logo.svg';
import { ethers } from "ethers";

The above imports are used to import React, Button from the MUI material library, the Ethereum logo, and ethers from the ethers library. React allows us to create and render components; Button allows us to create a button component; the Ethereum logo allows us to display the Ethereum logo; and ethers allows us to access the Ethereum blockchain.

Step 7: Create different States

In the WalletCard component, we will be creating three different states using the useState hook. The first is declaring a state variable called “errorMessage” and a function called “setErrorMessage” which will be used to change the value of the state variable. The initial value of the state variable is set to null. The second declares a state variable called “defaultAccount” and a function called “setDefaultAccount” which will be used to change the value of the state variable. The initial value of the state variable is set to null. The third and final line declares a state variable called “userBalance” and a function called “setUserBalance” which will be used to change the value of the state variable. The initial value of the state variable is set to null.

const [errorMessage, setErrorMessage] = useState(null);
const [defaultAccount, setDefaultAccount] = useState(null);
const [userBalance, setUserBalance] = useState(null);

Step 8: Connecting with Metamask

Next, we will create a function called connectwalletHandler which will make a request for permission to connect to MetaMask. You can copy and paste the code below:

const connectwalletHandler = () => {
if (window.ethereum) {
provider.send("eth_requestAccounts", [])
.then(async () => {
await accountChangedHandler(provider.getSigner());
})
} else {
setErrorMessage("Please Install MetaMask!!!");
}
}

The above code is a connectwalletHandler function that is used to handle the connection with a wallet provider. It first checks if the browser window has Metamask enabled, and if so, it sends an eth_requestAccounts request to the provider and then calls the accountChangedHandler function with the provider’s signer as an argument. Finally, if MetaMask is not enabled, it sets an error message informing the user to install MetaMask.

Step 9: Let’s build the Connect Button

We will develop a button that allows a user to connect to Ethereum. This button will call the function onClick. When this button is clicked, we will connect to MetaMask.

<Button
style={{ background: defaultAccount ? "#A5CC82" : "white" }}
onClick={connectwalletHandler}>
{defaultAccount ? "Connected!!" : "Connect"}
</Button>

The defaultAccount displays the wallet address, and we use the wallet address to show connected when the address is available. Otherwise, it should just show "connect."

Step 10: Log in to MetaMask

Upon connecting to MetaMask, we see a login prompt.

Step 11: Display User's Wallet Address

To handle the wallet address of the account and balance we signed up for or any other newly created account, we created an async function that awaits the provider.getSigner() function passed as a parameter to the accountChnagedHandler function. The accountChangedHandler contains the following:

const accountChangedHandler = async (newAccount) => {
const address = await newAccount.getAddress();
setDefaultAccount(address);
}

Inside this function from the code above, we pass a new parameter, newAccount, which is assigned to the provider.signer(), so we can access the getAddress() function and pass the address to our state variable using the account setter setDefaultAccount(address).

To display the wallet address, we will call the defaultAccount variable.

<h4 className="walletAddress">Address:{defaultAccount}</h4>

Step 12: Display User Wallet Balance

This section will show us how to get the user balance from the blockchain.

const accountChangedHandler = async (newAccount) => {
const address = await newAccount.getAddress();
setDefaultAccount(address);
const balance = await newAccount.getBalance()
setUserBalance(ethers.utils.formatEther(balance));
await getuserBalance(address)
}

Based on the above code, we can access the balance of the wallet using the provider.signer() was passed as newAccount, using the getBalance() function, but this would return a hexadecimal value that would be very large and unreadable, so we have to convert it from Wei to Ether (Wei is the smallest denomination of Ether). To do this, we will do the following

setUserBalance(ethers.utils.formatEther(balance));

Next, we will pass the address into getuserBalance() to be specific as to what wallet we will be needing its balance for.

const getuserBalance = async (address) => {
const balance = await provider.getBalance(address, "latest")
}

Inside the getuserBalance() function, we will pass the address to the provider.getBalance() takes the address and blockTag as parameters. To render it in our UI, use the code below

<div className="balanceDisplay">
<h3>
Wallet Amount: {userBalance}
</h3>
</div>

Hurray..! You should have something like this

Congratulations 🥳 for coming this far. Your code should look like this:

import React, { useState } from 'react';
import Button from '@mui/material/Button';
import Ethereum from './logo.svg';
import { ethers } from "ethers";

const provider = new ethers.BrowserProvider(window.Ethereum)

const WalletCard = () => {
const [errorMessage, setErrorMessage] = useState(null);
const [defaultAccount, setDefaultAccount] = useState(null);
const [userBalance, setUserBalance] = useState(null);
const connectwalletHandler = () => {
if (window.Ethereum) {
provider.send("eth_requestAccounts", []).then(async () => {
await accountChangedHandler(provider.getSigner());
})
} else {
setErrorMessage("Please Install Metamask!!!");
}
}
const accountChangedHandler = async (newAccount) => {
const address = await newAccount.getAddress();
setDefaultAccount(address);
const balance = await newAccount.getBalance()
setUserBalance(ethers.formatEther(balance));
await getuserBalance(address)
}
const getuserBalance = async (address) => {
const balance = await provider.getBalance(address, "latest")
}
return (
<div className="WalletCard">
<img src={Ethereum} className="App-logo" alt="logo" />
<h3 className="h4">
Welcome to React DApp Metamask
</h3>
<Button
style={{ background: defaultAccount ? "#A5CC82" : "white" }}
onClick={connectwalletHandler}>
{defaultAccount ? "Connected!!" : "Connect"}
</Button>
<div className="displayAccount">
<h4 className="walletAddress">Address:{defaultAccount}</h4>
<div className="balanceDisplay">
<h3>
Wallet Amount: {userBalance}
</h3>
</div>
</div>
{errorMessage}
</div>
)
}
export default WalletCard;

So let’s do a little bit of a recap on each line and what it does: Line 1 imports React and useState from React to use state in the component; Line 2 imports the Button component from Material UI; Line 4 imports the ethers.js library and the Web3Provider from ethers; and Line 5 creates a new Web3Provider instance that uses the window.Ethereum object, which is the Ethereum network. Line 6 handles creating the WalletCard component, and lines 7–9 handle the setting of the state variables for the user’s wallet address, wallet amount, and any errors. Line 11 creates the connectwalletHandler function, which will be called when the user clicks the “Connect” button. Lines 12–17 check if the user has installed Metamask, and if so, call the accountChangedHandler function, which will get the user’s wallet address and wallet amount. Lines 19–24 handle the accountChangedHandler function, which will get the user’s wallet address and amount. Lines 25–29 create the getuserBalance function, which will be used to get the user’s current balance. Then finally, lines 31–51 render the wallet card component in the UI, which displays the user’s wallet address and wallet amount.

Note: Here is the github source code for the demo I made, which accurately illustrates the entire procedure, along with the code showcasing the complete implementation.

Conclusion

In this article, we acquired knowledge on how to build a DApp with the Ethers.js library and React framework, which is an excellent starting point for interacting with decentralized applications. The next step is to figure out how to construct smart contracts and use them in our decentralized applications.

New to trading? Try crypto trading bots or copy trading on best crypto exchanges

Join Coinmonks Telegram Channel and Youtube Channel get daily Crypto News

Also, Read

--

--

Williams Peter
Coinmonks

Ex-CEO at Kosmero | FullStack Engineer (MERN) | Web2 | Web3 Frontend Engineer | Technical Writer | Developer Relations