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 !'
}
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 Balance
button :
Done !
We’ve got a fonctional connection to the bridge, usable in all the application with a Context !