Usage example of the DERO bridge api with React and Typescript

DERO RPC BRIDGE API Tutorial

For this example we will be using the React Framework with vite and yarn tools.

Lets get right into it:

Quick app setup

# create project using vite
yarn create vite

Then enter the project name, select react and react-ts.

When the project is created, you need to move to this folder, add the bridge to your project and install packages :

# Move into the project folder
cd PROJECT_NAME # change that to your actual project name

# Add the bridge to your project
yarn add dero-rpc-bridge-api

# Install dependencies and start dev server
yarn && yarn dev

Now you should have a running development server!

Initialising the connection with the Bridge

Let’s start with the main component (App.ts):

import './App.css'

// Simply return a div
function App() {

  return (
    <div className='App'>
    </div>
  )
}

We will declare a state variable bridge that will hold the object imported from the dero-rpc-bridge-api.

import { useState } from 'react' // Import useState
import './App.css'

import DeroBridgeApi from 'dero-rpc-bridge-api' // Import the brigde

function App() {
  // Add the state variable using useState hook
  const [bridge, setBridge] = useState<DeroBridgeApi>()

  return (
    <div className='App'>
    </div>
  )
}

Then add a button to connect to the bridge !

import { useCallback, useState } from 'react' // Import useCallback
import './App.css'

import DeroBridgeApi from 'dero-rpc-bridge-api'


function App() {

  const [bridge, setBridge] = useState<DeroBridgeApi>()

  // Add the button callback function
  const connect = useCallback(async () => {
    ...
  }, [])

  return (
    <div className='App'>
      // Add the button calling the connect function on click
      <button onClick={connect}>connect</button>
    </div>
  )
}

We will also setup a state variable, to handle the status of the connection to the bridge. We will start by declaring an enumeration of the different states:

In utils/connection-status.ts :

// Declare the enumeration. We will move this in a separate file later to 
export enum ConnectionStatus {
  NotConnected = "not connected",
  Connected = "connected to the bridge!",
  Connecting = "connecting...",
  Failed = 'connection failed !'
}

And declare the variable in App.tsx:

import { useCallback, useState } from 'react' 
import './App.css'

import DeroBridgeApi from 'dero-rpc-bridge-api'
import { ConnectionStatus } from './utils/connection-status' // Import ConnectionStatus enumeration


function App() {

  const [bridge, setBridge] = useState<DeroBridgeApi>()
  // Add status initialized with NotConnected
  const [status, setStatus] = useState<ConnectionStatus>(ConnectionStatus.NotConnected) 

  const connect = useCallback(async () => {
    ...
  }, [])

  return (
    <div className='App'>
      <button onClick={connect}>connect</button>
    </div>
  )
}

We’re almost done with the first part ! We need to handle the click of the button :

  ...

  const connect = useCallback(async () => {

    // Start by setting the status of the connection to connecting when we click.
    setStatus(ConnectionStatus.Connecting);

    // Load the bridge in a local constant variable
    const deroBridgeApi = new DeroBridgeApi();

    // Initialise the object and handle the different Promise cases
    deroBridgeApi.init()
      .then(() => { // When connection is successful
        // We set status to Connected !
        setStatus(ConnectionStatus.Connected);
      })
      .catch((err: any) => { // If an error occured
        // We just put the error message as the status. We could handle it better, but it works for this example !
        setStatus(err.message);
      })

    // Then we save the object in the app's state variable.
    setBridge(deroBridgeApi);
    
  }, [])

  ...

Great ! Now we should end up with this :

App.tsx

import { useCallback, useState } from 'react'
import logo from './logo.svg'
import './App.css'

// @ts-ignore
import DeroBridgeApi from 'dero-rpc-bridge-api'
import { ConnectionStatus } from './utils/connection-status'



function App() {
  const [bridge, setBridge] = useState<DeroBridgeApi>()
  const [status, setStatus] = useState<ConnectionStatus>()

  const connect = useCallback(async () => {
    setStatus(ConnectionStatus.Connecting);

    const deroBridgeApi = new DeroBridgeApi();

    deroBridgeApi.init()
      .then(() => {
        setStatus(ConnectionStatus.Connected);
      })
      .catch((err: any) => {
        setStatus(err.message);
      })

    setBridge(deroBridgeApi);
  }, [])

  return (
    <div className='App'>
      <button onClick={connect}>connect</button>
      <div>Status: {status}</div>
    </div>
  )
}

export default App

connection-status.ts

export enum ConnectionStatus {
    NotConnected = "not connected",
    Connected = "connected to the bridge!",
    Connecting = "connecting...",
    Failed = 'connection failed !'
}  

Then when you open :

And click on connect :

Create a context to access the bridge anywhere in the app.

Now we’ll setup a context with the useContext hook in App.tsx:

import { useCallback, useState } from 'react'
import './App.css'

// @ts-ignore
import DeroBridgeApi from 'dero-rpc-bridge-api'
import React from 'react';
import GetBalanceComponent from './components/GetBalanceComponent';
import { ConnectionStatus } from './utils/connection-status';


// Global context variable to use all across the app
export const DeroContext = React.createContext<DeroBridgeApi>(null);


// App component
function App() {

  const [bridge, setBridge] = useState<DeroBridgeApi>()
  const [status, setStatus] = useState<ConnectionStatus>(ConnectionStatus.NotConnected)

  // Callback when we click the connect button
  const connect = useCallback(async () => {
    setStatus(ConnectionStatus.Connecting);
    const deroBridgeApi = new DeroBridgeApi();
    deroBridgeApi.init()
      .then(() => {
        setStatus(ConnectionStatus.Connected);
      })
      .catch((err: any) => {
        setStatus(err.message);
      })
    setBridge(deroBridgeApi);
  }, [])

  return (
    // Pass the bridge object to the context provider
    // The app has a title a button calling the connect callback defined earlier and a custom components defined in components/
    <DeroContext.Provider value={bridge}>
      
      // App wrapper
      <div className='App'>
        <h1>Dero RPC Bridge API example app</h1>
        
        <button onClick={connect}>connect</button>
        
        <div>Status:</div>
        <div><i>{status}</i></div>
        
        // A GetBalanceComponent that we are going to create soon !
        <GetBalanceComponent status={status}/>
        

      </div>
    </DeroContext.Provider>
  )
}

export default App

Then create a component that gets the balance in components/GetBalanceComponent.ts:

import { useCallback, useContext, useState } from "react"
import { DeroContext } from "../App";
import { ConnectionStatus } from "../utils/connection-status";

// Define the props of our component
interface Props {
    status: ConnectionStatus
}

// GetBalanceComponent definition
export default (props: Props) => {
    // Balance and error message, updated when clicking the Get Balance button
    const [balance, setBalance] = useState<string | number>('unknown');
    const [errorMessage, setErrorMessage] = useState<string>();

    // Here we get the bridge object from the context
    const deroBridgeApi = useContext(DeroContext);
    
    // Callback when clicking the Get Balance button
    const getBalance = useCallback(async () => {
        // Call the GetBalance method from the wallet
        deroBridgeApi.wallet('get-balance')
            .then((response: any) => { // When successful
                // Update the balance state of the component
                setBalance(response.data.result.balance / 100000)
                // Empty the error message
                setErrorMessage("");
            })
            .catch((err: any) => { // When failed
                // Update the balance to unknown
                setBalance('unknown');
                // Update the error message
                setErrorMessage(err.message);
            })
    }, [props.status]) // Update the function when the connection status change so that the context actually provide a deroBridgeApi object

    // We render the component only if status is connected 
    if (props.status == ConnectionStatus.Connected) {
        return <div className='GetBalanceComponent'>
            // Title
            <h2>GetBalance Component</h2>

            // Button
            <button onClick={getBalance}>Get Wallet Balance</button>

            // Balance display
            <div>Balance:</div>
            <div>{balance}</div>
            <div>{errorMessage}</div>
        </div>
    } else {
        return <div></div>
    }
    
}

And it gives us :


Clicking on the Connect button :

Clicking on the Get Balancebutton :

Done !

We’ve got a fonctional connection to the bridge, usable in all the application with a Context !

GitHub

View Github