# How to use Web3-react to develop DApp

By [fangjun.eth](https://paragraph.com/@fangjun) · 2022-01-30

---

Web3-react is a popular library used in blockchain, DApp and web3 development. It has more than 2800 stars and has been used by more than 10000 repo's on Github.

Note: If you have known `web3-react`, you can go directly to section 1 for how-to guide.

Last Updated: 2022/01/30

0\. What is `web3-react`?
-------------------------

Before starting the journey, I will give an overview of the stack and technology we use:

*   Front-end: React, Next.js, Chakra UI, TypeScript
    
*   Blockchain API: Ethers.js
    
*   Development Environment: Hardat, MetaMask, Ethereum testnet
    

`web3-react` is a react/ethers.js framework for building modern Ethereum DApp developed by Uniswap Engineering Lead Noah Zinsmeister. It works between Front-end and blockchain API.

> At a high level, web3-react is a state machine which ensures that certain key pieces of data (the user's current account, for example) relevant to your dApp are kept up-to-date.
> 
> To this end, web3-react uses Context to efficiently store this data, and inject it wherever you need it in your application. (via [web3-react v6 docs](https://github.com/NoahZinsmeister/web3-react/tree/v6/docs#overview))

It is a react library and the underlying blockchain API is `ethers.js`. The stable version is v6, and currently v8 is in beta. You can find `web3-react` repo at: [https://github.com/NoahZinsmeister/web3-react](https://github.com/NoahZinsmeister/web3-react)

As it is widely used, I am surprised to find that there are very few documents. So far, I can only refer to 4 documents:

*   source code of web3-react (v6 and v8 beta)
    
*   example in the package (v6 and v8 beta)
    
*   documents for web3-react v6
    
*   a tutorial on Consensys blog by Lorenzo Sicilia
    

There are some main changes from v6 to 8. Widely used hooks `useWeb3React` is tagged with comment "for backwards compatibility only".

I can foresee that Version 8 of `web3-react` will be widely used as it can meet the increasing demand of web3. I wrote down this tutorial to help developers to use it, both for v6 and v8(beta).

Useful links: Source code and documents for web3-react v6:

*   source code [https://github.com/NoahZinsmeister/web3-react/tree/v6](https://github.com/NoahZinsmeister/web3-react/tree/v6)
    
*   documents [https://github.com/NoahZinsmeister/web3-react/tree/v6/docs](https://github.com/NoahZinsmeister/web3-react/tree/v6/docs)
    

[Lorenzo's Web3-React Tutorial](https://consensys.net/blog/developers/how-to-fetch-and-update-data-from-ethereum-with-react-and-swr/) is a great help for this how-to guide, and I copied the sample code from it. Great thanks. The tutorial is great as it illustrates the strategy to sync data between blockchain and DApp:

> "SWR and Ether.js are two nice libraries to work with if you want to streamline your data fetching strategy with Ethereum dapp."

1\. Set up playground: create a Next.js project
-----------------------------------------------

First, we start a Next.js project to write DAPP using `web3-react`. Then, we add dependencies. Follow these 6 steps:

### 1.1 Create a project:

    yarn create next-app playeth --typescript
    cd playeth
    

### 1.2 Use `src` as our source code directory:

    mkdir src
    mv pages src/pages
    mv styles src/styles
    

Edit `tsconfig.json`, add:

        "baseUrl": "./src",
    

### 1.3 Clear `index.tsx`:

Make `index.tsx` simple.

    import type { NextPage } from 'next'
    import styles from '../styles/Home.module.css'
    
    const Home: NextPage = () => {
      return (
        <div>
          <main className={styles.main}>
            <h2>
              Welcome to playground
            </h2>
          </main>
        </div>
      )
    }
    export default Home
    

### 1.4 Run project and view it at: [http://localhost:3000/](http://localhost:3000/)

### 1.5 Add dependencies

We will use `ethers.js`, `web3-react` and etc here.

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

`web3-react` installed is stable version 6.x.x.

If you would like to add only `ethers.js` component used, you can replace the first command to: `yarn add @ethersproject/providers`

2\. Connect to blockchain using Web3-react, ethers and MetaMask
---------------------------------------------------------------

The main difference between DApp (web3 app) and traditional web app is that DApp connects to blockchain instead of a centralized server for 1) user login and authorization, 2) data about data and 3) functionality such as DeFi, NFT, Game, DAO governance.

When DApps are used in desktop browsers, they are made possible with three things:

*   MaskMask wallet on the user side
    
*   Ethers.js between browser/server and blockchain endpoint
    
*   React and Web3-react on the server/browser
    

Let's start to make a DApp with `web3-react`. We will use its two parts:

*   Web3ReactProvider, context
    
*   useWeb3React, hooks
    

Please note that there is a big upgrade from v6 to v8. `useWeb3React` is tagged with comment "for backwards compatibility only".

### 2.1 Provider in `_app.tsx`

Add context provider `<Web3ReactProvider>` in `_app.tsx`:

    import '../styles/globals.css'
    import type { AppProps } from 'next/app'
    
    import { Web3ReactProvider } from '@web3-react/core'
    import { Web3Provider } from '@ethersproject/providers'
    
    function getLibrary(provider: any): Web3Provider {
      const library = new Web3Provider(provider)
      library.pollingInterval = 12000
      return library
    }
    
    function MyApp({ Component, pageProps }: AppProps) {
      return (
        <Web3ReactProvider getLibrary={getLibrary}>
          <Component {...pageProps} />
        </Web3ReactProvider>
      )
    }
    
    export default MyApp
    

### 2.2 Edit `index.tsx`

Use `useWeb3React` to connect to blockchain using an injected provider by MetaMask. You can call it directly through `windows.ethereum`. MetaMask Ethereum Provider API docs is [here](https://docs.metamask.io/guide/ethereum-provider.html#table-of-contents).

You need to have MetaMask extension installed in your Chrome browser.

Edit `index.tsx` to provide a button to connect blockchain using MetaMask wallet and its blockchain provider injected to browser.

    import type { NextPage } from 'next'
    import styles from '../styles/Home.module.css'
    import { useEffect } from 'react'
    
    import { useWeb3React } from '@web3-react/core'
    import { Web3Provider } from '@ethersproject/providers'
    import { InjectedConnector } from '@web3-react/injected-connector'
    
    const ConnectWallet = () => {
      const injectedConnector = new InjectedConnector({supportedChainIds: [1,3, 4, 5, 42, ],})
      const { chainId, account, activate, active,library } = useWeb3React<Web3Provider>()
      const onClick = () => {
        activate(injectedConnector)
      }
    
      useEffect(() => {
        console.log(chainId, account, active)
        },);
    
      return (
        <div>
          <div>ChainId: {chainId}</div>
          <div>Account: {account}</div>
          {active ? (
            <div>✅ </div>
          ) : (
            <button type="button" onClick={onClick}>
              Connect Connect
            </button>
          )}
        </div>
      )
    }
    
    const Home: NextPage = () => {
      return (
        <div >
          <main className={styles.main}>
            <h2 >Welcome to playground</h2>
            <ConnectWallet />
          </main>
        </div>
      )
    }
    
    export default Home
    

What do we do? We add a `ConnectWallet` Component for display account and connect to wallet.

*   Click connect Wallet button, `activate(injectedConnector)` of `useWeb3React` hook is called.
    
*   When connected, display `chainId` and `account`.
    

Run `yarn dev`, we can play with this simple DApp at: [http://localhost:3000/](http://localhost:3000/)

![Image description](https://storage.googleapis.com/papyrus_images/f340671a1a8ff1ba329f5e4fae7e2f9483ce66b8e33bca054e6023593aa9341a.png)

Image description

Note: If you want to truly disconnect your wallet from this page, disconnect from MetaMask.

3\. Get data from Ethereum Mainnet: Read Blockchain
---------------------------------------------------

In Section 2, we have established an environment to interact with blockchain. In this section, we will try to get data from Ethereum Mainnet.

### 3.1 Query data and display using useState and useEffect

Make some changes in `index.tsx`, please note this is a quick and dirty code snippet just for illustration.

      const [balance,setBalance]= useState("")
    ...
      useEffect(() => {
        library?.getBalance(account).then((result)=>{
          setBalance(result/1e18)
        })
        },);
    ...
          <div>Balance: {balance}</div>
    

### 3.2 Query data using SWR

SWR ([https://swr.now.sh/](https://swr.now.sh/)) means Stale-While-Revalidate. [Lorenzo's Web3-React Tutorial](https://consensys.net/blog/developers/how-to-fetch-and-update-data-from-ethereum-with-react-and-swr/) suggests using this strategy. A quote about SWR:

> SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.

After insatll `swr`, edit `index.tsx`

    import useSWR from 'swr'
    ...
        const fetcher = (library) => (...args) => {
          const [method, ...params] = args
          console.log("fetcher",method, params)
          const result = librarymethod
         return librarymethod
        }
    
        const BalanceSWR  = () => {
          const { account, library } = useWeb3React<Web3Provider>()
          const { data: balance } = useSWR(['getBalance', account, 'latest'], {
            fetcher: fetcher(library),
          })
          console.log(balance)
          if(!balance) {
            return <div>...</div>
          }
          return <div>Balance: Ξ {balance/1e18}</div>
        }  
    ...
          {active && <BalanceSWR />}
    

Lorenzo's Web3-React Tutorial explains:

> As you can see, it is a partially applied function. In that way, I can inject the library (my Web3Provider) when I configure the fetcher. Later, every time a key changes, the function can be resolved by returning the required promise.

### 3.3 Update data in real-time

The pro of using SWR is that it can update data in real-time.

We will follow Lorenzo's Web3-React tutorial to do this.

The feature used is SWR's `mutate` function.

*   Listen to Etheruem block number change: ethers.provider.on()
    
*   Use SWR mutate to trigger refresh
    

Edit `BalanceSWR` component in `index.tsx`:

          const { account, library } = useWeb3React<Web3Provider>()
          const { data: balance,mutate } = useSWR(['getBalance', account, 'latest'], {
            fetcher: fetcher(library),
          })
    
          useEffect(() => {
            // listen for changes on an Ethereum address
            console.log(`listening for blocks...`)
            library.on('block', () => {
              console.log('update balance...')
              mutate(undefined, true)
            })
            // remove listener when the component is unmounted
            return () => {
              library.removeAllListeners('block')
            }
            // trigger the effect only on component mount
          }, [])
    

Lorenzo's tutorial has more on interacting with smart contract and listening to smart contract events. You can continue to read it and do experiments: [https://consensys.net/blog/developers/how-to-fetch-and-update-data-from-ethereum-with-react-and-swr/](https://consensys.net/blog/developers/how-to-fetch-and-update-data-from-ethereum-with-react-and-swr/)

We will go to Web3-react version 8 to see what has been changed.

4\. Dive into Web3-react Version 8
----------------------------------

There is an example to demostate how to use it. We will take some code snippets from it directly. You can find the example at packages/example/

### STEP 1 Create an example project

Create a next.js project just like we did in section 1.

Edit package.json to add dependencies:

        "@ethersproject/bignumber": "^5.4.2",
        "@ethersproject/experimental": "^5.5.0",
        "@ethersproject/providers": "^5.5.1",
        "@ethersproject/units": "^5.4.0",
        "@walletconnect/ethereum-provider": "^1.7.1",
        "@web3-react/core": "8.0.6-beta.0",
        "@web3-react/eip1193": "8.0.2-beta.0",
        "@web3-react/empty": "8.0.2-beta.0",
        "@web3-react/metamask": "8.0.3-beta.0",
        "@web3-react/network": "8.0.2-beta.0",
        "@web3-react/types": "8.0.2-beta.0",
        "@web3-react/url": "8.0.2-beta.0",
        "@web3-react/walletconnect": "8.0.4-beta.0",
        "@web3-react/walletlink": "8.0.4-beta.0",
    

Run command to install dependencies:

### STEP 2: AccountsComponent

Create `components/AccountsComponent.tsx` based on: [https://github.com/NoahZinsmeister/web3-react/blob/main/packages/example/components/Accounts.tsx](https://github.com/NoahZinsmeister/web3-react/blob/main/packages/example/components/Accounts.tsx)

    import type { BigNumber } from '@ethersproject/bignumber'
    import { formatEther } from '@ethersproject/units'
    import type { Web3ReactHooks } from '@web3-react/core'
    import { useEffect, useState } from 'react'
    
    function useBalances(
      provider?: ReturnType<Web3ReactHooks['useProvider']>,
      accounts?: string[]
    ): BigNumber[] | undefined {
      const [balances, setBalances] = useState<BigNumber[] | undefined>()
    
      useEffect(() => {
        if (provider && accounts?.length) {
          let stale = false
    
          void Promise.all(accounts.map((account) => provider.getBalance(account))).then((balances) => {
            if (!stale) {
              setBalances(balances)
            }
          })
    
          return () => {
            stale = true
            setBalances(undefined)
          }
        }
      }, [provider, accounts])
    
      return balances
    }
    
    export function AccountsComponent({
      accounts,
      provider,
      ENSNames,
    }: {
      accounts: ReturnType<Web3ReactHooks['useAccounts']>
      provider: ReturnType<Web3ReactHooks['useProvider']>
      ENSNames: ReturnType<Web3ReactHooks['useENSNames']>
    }) {
      const balances = useBalances(provider, accounts)
    
      if (accounts === undefined) return null
    
      return (
        <div>
          Accounts:{' '}
          <b>
            {accounts.length === 0
              ? 'None'
              : accounts?.map((account, i) => (
                  <ul key={account} style={{ margin: 0, overflow: 'hidden', textOverflow: 'ellipsis' }}>
                    <li>{ENSNames?.[i] ?? account}</li>
                    <li>{balances?.[i] ? ` (Ξ${formatEther(balances[i])})` : null}</li>
                  </ul>
                ))}
          </b>
        </div>
      )
    }
    

Some explanations:

*   A component to display ENS/Address and ether balance of the account
    
*   Using `getBalance` function of web3 provider to query ether balance
    

### STEP 3: MetaMaskCard

Create `components/MetaMaskCard.tsx`. MetaMaskCard is based on: MetaMaskCard, Connect, Status component in [https://github.com/NoahZinsmeister/web3-react/tree/main/packages/example/components](https://github.com/NoahZinsmeister/web3-react/tree/main/packages/example/components)

    import type { Web3ReactHooks } from '@web3-react/core'
    import { AccountsComponent } from './AccountsComponent'
    import { initializeConnector } from '@web3-react/core'
    import { MetaMask } from '@web3-react/metamask'
    
    const [metaMask, hooks] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
    const {  useChainId, useAccounts, useError, useIsActivating, useIsActive, useProvider, useENSNames } = hooks
    
    function Connect({
      isActivating,
      error,
      isActive,
    }: {
      chainId: ReturnType<Web3ReactHooks['useChainId']>
      isActivating: ReturnType<Web3ReactHooks['useIsActivating']>
      error: ReturnType<Web3ReactHooks['useError']>
      isActive: ReturnType<Web3ReactHooks['useIsActive']>
    }) {
    
      if (error) {
        return (
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            <button
              onClick={() => metaMask.activate()}
            >
              Try Again?
            </button>
          </div>
        )
      } else if (isActive) {
        return (
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            <button onClick={() => metaMask.deactivate()}>Disconnect</button>
          </div>
        )
      } else {
        return (
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            <button
              onClick={
                isActivating
                  ? undefined
                  : () => metaMask.activate()
              }
              disabled={isActivating}
            >
              Connect
            </button>
          </div>
        )
      }
    }
    
    function Status({
      isActivating,
      error,
      isActive,
    }: {
      isActivating: ReturnType<Web3ReactHooks['useIsActivating']>
      error: ReturnType<Web3ReactHooks['useError']>
      isActive: ReturnType<Web3ReactHooks['useIsActive']>
    }) {
      return (
        <div>
          {error ? (
            <>
              🔴 {error.name ?? 'Error'}
              {error.message ? `: ${error.message}` : null}
            </>
          ) : isActivating ? (
            <>🟡 Connecting</>
          ) : isActive ? (
            <>🟢 Connected</>
          ) : (
            <>⚪️ Disconnected</>
          )}
        </div>
      )
    }
    
    export default function MetaMaskCard() {
      const chainId = useChainId()
      const accounts = useAccounts()
      const error = useError()
      const isActivating = useIsActivating()
    
      const isActive = useIsActive()
    
      const provider = useProvider()
      const ENSNames = useENSNames(provider)
    
      return (
          <div style={{border: '1px solid'}}>
            <b>MetaMask</b>
            <Status isActivating={isActivating} error={error} isActive={isActive} />
            <AccountsComponent accounts={accounts} provider={provider} ENSNames={ENSNames} />
            <Connect chainId={chainId} isActivating={isActivating} error={error} isActive={isActive} />
          </div>
    
      )
    }
    

Some explanations:

*   Three components: MetaMaskCard, Connect, Status
    
*   Connect component provide a button user can click to connect MetaMask wallet by calling `metaMask.activate()`
    
*   Status Component display status according to `isActivating` and `isActive`
    

We get all the needed hooks here:

    const [metaMask, hooks] = initializeConnector<MetaMask>((actions) => new MetaMask(actions))
    const {  useChainId, useAccounts, useError, useIsActivating, useIsActive, useProvider, useENSNames } = hooks
    

### STEP 4: `index.tsx`

Using next.js dynamic import to import MetaMaskCard.

    import type { NextPage } from 'next'
    import styles from 'styles/Home.module.css'
    
    import dynamic from 'next/dynamic'
    
    const MetaMaskCard = dynamic(() => import('../components/MetaMaskCard'), { ssr: false })
    
    const Home: NextPage = () => {
      return (
        <div>
          <main  className={styles.main}>
            <h2>
              Welcome to playground
            </h2>
            <MetaMaskCard />
          </main>
        </div>
      )
    }
    export default Home
    

Run command `yarn dev` and visit the sample app at: localhost:3000

In sum, web3-react provides a handy tool with context and hooks between react and ethers. Enjoy it.

---

*Originally published on [fangjun.eth](https://paragraph.com/@fangjun/how-to-use-web3-react-to-develop-dapp)*
