Skip to main content

How to build a React application integrated with Nevermined

The idea of this tutorial is give a quick go through about using the Nevermined Catalog of React components to support the development of dApps using the Nevermined environment. Nevermined Catalog is a library that provides some React components to make it easier the integration with Nevermined technologies. You can find more info in the documentation.

Prerequisites

The tutorial assumes your familiarity with blockchain, and general programming.

Let's go

Instructions for following along locally using your preferred text editor.

Setup the React app

  1. Make sure you have a recent version of Node.js installed.
  2. Follow the installation instructions for Create React App to make a new project. Or simply run npx create-react-app my-nevermined-app --template typescript.
  3. Move to the my-nevermined-app directory cd my-nevermined-app.
  4. Run yarn add @nevermined-io/catalog-core or npm install --save @nevermined-io/catalog-core depending of your favourite package manager.
  5. Run yarn run start and open http://localhost:3000 and you will see the progress.

image Screenshot of the current application status.

Create your Nevermined dApp

Once the react app is running and you have your catalog dependency, the next step will be to setup the configuration:

  1. Donwload Nevermined abi and store them in a folder named contracts in the public folder. These abis are the interface to iteract with Nevermined contracts deployed on the blockchain. Visit ABI specification to learn more about.
  2. Create a config.ts file and provide the Nevermined config as follow:
tip

For the REACT_APP_NODE_URI you can connect to a QuickNode or Infura puclic Node. Both services allow to connect your dApp to different blockchain networks. You will need to connect to iteract with Nevermined contracts.

import { Config } from '@nevermined-io/nevermined-sdk-js';

// URL where run the app
export const serviceUri = process.env.REACT_APP_SERVICE_URI || 'http://localhost:3445';
// Ethereum address own by the node.
export const neverminedNodeAddress = process.env.REACT_APP_GATEWAY_ADDRESS || '0x5838B5512cF9f12FE9f2beccB20eb47211F9B0bc';
// Node service
export const neverminedNodeUri = process.env.REACT_APP_GATEWAY_URI || 'https://node.mumbai.public.nevermined.network';
// Fauce uri to get some tokens.
export const faucetUri = process.env.REACT_APPREACT_APP_FAUCET_URI_FAUCET_URI || 'https://faucet.mumbai.public.nevermined.rocks';
// Blockchain node
export const web3ProviderUri = process.env.REACT_APP_NODE_URI || 'https://matic-mumbai.chainstacklabs.com';
// Chain id of your network
export const acceptedChainId = process.env.REACT_APP_ACCEPTED_CHAIN_ID || '80001'; // for Mumbai
//URL where run the root of the app is. Important to find public folder with abis.
export const rootUri = process.env.REACT_APP_ROOT_URI || 'http://localhost:3445';
// Marketplace API uri to store metadata.
export const marketplaceUri = process.env.REACT_APP_MARKETPLACE_URI || 'https://marketplace-api.mumbai.public.nevermined.network';

export const appConfig: Config = {
//@ts-ignore
web3Provider: typeof window !== 'undefined' ? window.ethereum : new ethers.providers.JsonRpcProvider(web3ProviderUri),
web3ProviderUri,
neverminedNodeUri,
faucetUri,
verbose: 2,
neverminedNodeAddress,
graphHttpUri: '',
marketplaceAuthToken: typeof window !== 'undefined' ? AuthToken.fetchMarketplaceApiTokenFromLocalStorage().token : '',
marketplaceUri,
artifactsFolder: `${rootUri}/contracts`,
newGateway: true
};

  1. Go to index.tsx and add the NeverminedProvider
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Catalog from '@nevermined-io/catalog-core';
import { appConfig } from './config';

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<Catalog.NeverminedProvider config={appConfig}>
<App />
</Catalog.NeverminedProvider>
</React.StrictMode>
);

reportWebVitals();
  1. After that you will be able to iteract with the Nevermined ecosystem. List did assets deployed updating your App.tsx
import Catalog from '@nevermined-io/catalog-core'
import React, { useEffect, useState } from 'react'

function App() {

const query = {
offset: 150,
page: 1,
query: {},
sort: {
created: 'desc'
}
};

const MultipleAssets = () => {
const { isLoading: isLoadingAssets, result } = Catalog.useAssets(query)
const [dids, setDids] = useState<string[]>()

useEffect(() => {
setDids(result?.results?.map(asset => asset.id))
}, [result])

const [filterQuery, setQuery] = useState("")

function filterItems(query: string) {
setQuery(query)
setDids(result?.results?.map(asset => asset.id)?.filter(item => item.includes(query)))
}

return (
<>
<input
type="search"
name="search-form"
id="search-form"
className="search-input"
placeholder="Search for..."
value={filterQuery}
onChange={(e) => filterItems(e.target.value)}
/>
<div>Assets: </div>
<div>
<ul>{!isLoadingAssets ? dids?.map(asset => <li key={asset}>{asset}</li>) : "Loading assets..."}</ul>
</div>
</>
)
}
return (
<div className="App">
<header className="App-header">
<MultipleAssets />
</header>
</div>
);
}

export default App;

Login with different providers

After see how it is possible list some data coming from the blockchain let's see how you can login with your Nevermined dApp using our catalog integration with different providers.

  1. Run yarn add @nevermined-io/catalog-providers or npm install --save @nevermined-io/catalog-providers depending of your favourite package manager. This library plan to give support to more wallet providers in near future. Stay tunned.

  2. As before, add the WalletProvider in index.tsx.

import {getClient, WalletProvider } from '@nevermined-io/catalog-providers'

...
<WalletProvider client={getClient()}>
<App />
</WalletProvider>
  1. Modify App.tsx to create a login button.
import { useWallet } from '@nevermined-io/catalog-providers'
import React from 'react'

const Login = () => {
const { login, walletAddress, logout, getConnectors} = useWallet()

return (
<div className='app'>
{!walletAddress ?
getConnectors().map(c =>
<button onClick={() => login(c)}>Connect to {c.name}</button>
)
:
<>
<p>{walletAddress}</UiText>
<button onClick={logout}>Logout</button>
</>
}
</div>
)
}
export default App;

You can find the source code in github.