Connect a wallet to a react app

This is the first blog post of the series I will publish during all the month. If you don't want to miss one follow me on twitter https://twitter.com/0xTiby or bookmark this thread : https://twitter.com/0xTiby/status/1620653654150897667 . In this blog post we will learn how to connect an Ethereum wallet to a react app.

What's needed

To be able to connect our wallet to our app we will need some 3rd party packages :

  • rainbowkit : RainbowKit is a React library that makes it easy to add wallet connection to your dapp. It's intuitive, responsive and customizable.
  • wagmi : wagmi is a collection of React Hooks containing everything you need to start working with Ethereum.
  • ethers : The ethers.js library aims to be a complete and compact library for interacting with the Ethereum Blockchain and its ecosystem
  • Next.JS : And of course a react application

The quick way with no config

The first thing to do is to create a next application by running :

npx create-next-app@latest --ts

--ts is optional if you don't want to use typescript remove it.

Next we install the packages

yarn add @rainbow-me/rainbowkit wagmi ethers

Now we can configure our wagmi client in our _app.tsx file.

import '@rainbow-me/rainbowkit/styles.css'

import { getDefaultWallets, RainbowKitProvider } from '@rainbow-me/rainbowkit'
import { configureChains, createClient, WagmiConfig } from 'wagmi'
import { mainnet, polygon, optimism, arbitrum } from 'wagmi/chains'
import { alchemyProvider } from 'wagmi/providers/alchemy'
import { publicProvider } from 'wagmi/providers/public'

const { chains, provider } = configureChains(
  [mainnet],
  [alchemyProvider({ apiKey: process.env.ALCHEMY_ID }), publicProvider()]
)

const { connectors } = getDefaultWallets({
  appName: 'Connect Wallet App',
  chains,
})

const wagmiClient = createClient({
  autoConnect: true,
  connectors,
  provider,
})

First we import all the necessary packages, next we configure our chains and node providers. In our case we are using the mainnet network and the Alchemy Provider. To use Alchemy provider you need an api key you can request here. And finaly we configure the wagmi client.

When the comfiguration is done we can add the React Context Providers for Wagmi and RainbowKit.

Still in our _app.tsx replace the App function with this :

<WagmiConfig client={wagmiClient}>
  <RainbowKitProvider chains={chains}>
    <Component {...pageProps} />;
  </RainbowKitProvider>
</WagmiConfig>

And now in the index.tsx we can import and use the ConnectButton component of RainbowKit

import { ConnectButton } from '@rainbow-me/rainbowkit'
import Head from 'next/head'
import styles from '@/styles/Home.module.css'

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
        <ConnectButton />
      </main>
    </>
  )
}

And that's it we have a working wallet connection.

Adding some customizations

Now that we have our wallet connected we can see that when connected we see the default RainbowKit UI. But if we don't want to use the default default components of RainbowKit we will need to handle part of the UI by ourself.

Let start by creating a new basic button components/Button.tsx :

import React from 'react'

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  label: string
  onClick?: () => void
}

export const Button = ({
  label,
  onClick,
  children,
}: ButtonProps): React.ReactElement => (
  <button
    onClick={onClick}
    style={{
      display: 'inline-block',
      outline: 0,
      cursor: 'pointer',
      backgroundColor: 'black',
      borderRadius: 4,
      padding: '8px 16px',
      fontSize: 16,
      fontWeight: 600,
      color: 'rgb(43, 108, 176)',
      border: '1px solid rgb(66, 153, 225)',
      lineHeight: 1,
    }}
  >
    {label}
  </button>
)

Next create a new component components/ConnectWallet.tsx and add this code :

import { useAccount, useEnsName } from 'wagmi'
import { useAccountModal, useConnectModal } from '@rainbow-me/rainbowkit'

import { Button } from './Button'
import React from 'react'

const ConnectWallet = (): React.ReactElement => {
  const { address, isConnected } = useAccount()
  const { data: ensName } = useEnsName({ address })
  const { openConnectModal } = useConnectModal()
  const { openAccountModal } = useAccountModal()

  const formattedAdr = address
    ? `${address.substring(0, 4)}${address.substring(
        address.length - 4,
        address.length
      )}`
    : ''

  if (isConnected) {
    return (
      <Button
        label={ensName ? `${ensName.substring(0, 16)}` : `${formattedAdr}`}
        onClick={openAccountModal}
      />
    )
  }

  return <Button label="Connect Wallet" onClick={openConnectModal} />
}

export default ConnectWallet

Here's what we did :

First we imported the useAccount and useEnsName hooks from wagmi to get the account address and the ens name. Then we imported the useAccountModal and useConnectModal hooks from RainbowKit to be able to open the account modal or the connect modal. Next we created a formattedAdr variable to display the first 4 and last 4 characters of the address.

And finally depending on the connection status we display a button with the ens name or the address and we can open the account modal. Or if the user is not connected we display the connect wallet button that open the connect modal.

We can replace the ConnectButton component in our index.tsx with our new component :

export default function Home() {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
        <div>
          <ConnectWallet />
        </div>
      </main>
    </>
  )
}

Fix issue with Next SSR

There is an issue with Next SSR and RainbowKit that will cause an error when you refresh the page. To fix this issue we need create a hook that will check if we are on the client side.

Create a new file hooks/useIsMounted.ts and add this code :

import * as React from 'react'

export function useIsMounted() {
  const [mounted, setMounted] = React.useState(false)

  React.useEffect(() => setMounted(true), [])

  return mounted
}

And use it like that in our components/ConnectWallet.tsx :

const ConnectWallet = (): React.ReactElement | null => {
const isMounted = useIsMounted()
const { address, isConnected } = useAccount()
const { data: ensName } = useEnsName({ address })
const { openConnectModal } = useConnectModal()
const { openAccountModal } = useAccountModal()

if (!isMounted) {
  return null
}
// ... rest of the previous code

Conclusion

Now you have a basic app with a wallet connected and you can start building your app with Wagmi and RainbowKit. The source code is available on Github

If you like this post you can follow me on Twitter, share this post with your friends.