Me On IT
Published on

MetaMask: EthereumContext And React

Authors

Last time we talked about how to integrate MetaMask into a website, more specifically, how to use the window.ethereum reference.

Now we go one step further and deal with the question how we can actually use Ethers/MetaMask on a complex React website.

Usually, they are passed as props to individual React components. Since these can be quite deeply nested, this quickly becomes complicated. The problem is called prop drilling.1

Here the React-EthereumContext comes into play. It prevents prop drilling. So all subcomponents will directly get access to context information if needed.

I have defined the context for this use case as follows:


const EthereumContext = createContext<EthersContextType>({
  ethersProvider: {
    web3Provider: null,
    web3ProviderSetter: null,
    lastBlock: null,
    lastBlockSetter: null,
    defaultMainNetProvider: ethers.getDefaultProvider('mainnet'),
  },
})

Because Typescript is used here (<EthersContextType>), it is possible to quickly extend the context quickly later and benefit from the type safety of Typescript.

  1. The MetaMask plugin as a component of the browser.
  2. DefaultMainNetProvider as a component of the Ethers library, that is used when no Ethereum Gateway has been found.
  3. lastBlock, the most recent block in the blockchain.

These are completely different objects in reality, but they are modeled and made available in a uniform way. Fascinating!

Where that context as a part of reality is needed, it can now be quickly included, such as in this component:

'use client'

import React, { useEffect, useState, useContext } from 'react'
import EthereumContext from '../../app/context/EthereumContext'
import { ethers } from 'ethers'

const CurrentNetwork: React.FC = () => {
  const context = useContext(EthereumContext)
  const [network, setNetwork] = useState<ethers.Network | null | undefined>(null)
  useEffect(() => {
    context?.ethersProvider?.web3Provider?.getNetwork().then((n) => setNetwork(n))
  }, [context?.ethersProvider?.web3Provider])
  return network ? <span>{network?.name}</span> : <span>`--`</span>
}

export default CurrentNetwork

This is a densely packed piece of code, but it benefits from the compactness that possible with TypeScript. If the EthereumContext API was not used, it would look much wilder and more complicated at this point. With a little basic knowledge of React, the code remains readable.

If you would like to learn more about this, you are welcome to here to have a look.

All that remains to be said is that anything is possible if you want to Ethereum and React together. You just have to know how to do it ...

Footnotes

  1. As always in software development, every extension harbors the risk that the application becomes increasingly complicated. Prop drilling is one example of this. So what to do? -- The React-EthereumContext is only one solution for this. There are also many other context APIs for React, but these must be integrated as external components. The React context has the advantage that it is already included.