Step-by-step: ReactJS dApp with the OnFlow emulator
Tags: smartcontract, react, blockchain, web3
Published: 2022-08-29 18:15:00

This article was created thanks to @vitiv (Yavhen Vitiv)!

---

In contrast to traditional applications that have their back-end parts running on centralized servers, dApp’s backend code runs autonomously in a decentralized network, like the OnFlow network.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kd3jwexsdwxixlisn6mo.png)

Smart contracts are programs used for agreement execution running when predetermined conditions are met. They allow involved parties to safely release funds, register vehicles, issue tickets, and even send notifications without intermediaries.

Smart contracts provide for high-level security and transparency, speed, accuracy, and notable cost efficiency. These can be used in various different industries, including healthcare, distribution, retail, and more. 
**dApps** allow to interact with smart contracts deployed on the blockchain.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsxtjm1ao133aawe5cfc.png)

**How to build a client-side application that interacts with smart contract in the blockchain network**

The application we're about to build will have the following functionality: 
- Log-in and log-out buttons
- User profiles
- The opportunity to update user profiles
- Account address directly connected to the blockchain network

## Step 1. Installing dependencies

1. Install the Node Package Manager (NPM)
2. Install the Flow CLI to run local emulator
3. Clone the fcl-dev-wallet repository in a separate folder to 
run dev wallet and the npm install

## Step 2. Setting up ReactJS dApp and the npm packages

Create a ReactJS dApp:
`npx create-react-app my-first-dapp
`
Install the OnFlow packages from the my-first-dapp directory:

`npm i @onflow/fcl @onflow/types
`

## Step 3. Setting up Tailwind CSS

This step is optional, but if you like, you can [read how to set up Tailwind CSS](https://tailwindcss.com/docs/guides/create-react-app).

## Step 4. Running the local emulator with the dev wallet

In the fcl-dev-wallet repository, you will have to run these two commands:
`flow emulator
npm run dev`

## Step 5. Creating the AppJS component with built-in log-in and log-out buttons

In the src/AppJS file, you can create the AppJS component with the log-in and log-out logic:

```js
mport * as fcl from "@onflow/fcl";

import './App.css';
import { useEffect, useState } from "react";

fcl
    .config()
    // Point App at Emulator REST API
    .put("accessNode.api", "http://localhost:8888")
    // Point FCL at dev-wallet (default port)
    .put("discovery.wallet", "http://localhost:8701/fcl/authn")


function App() {

    const [isLogged, setIsLogged] = useState(false);
    const [user, setUser] = useState();

    useEffect(() => {
        fcl.currentUser.subscribe((account) => {
            setUser(account);
            setIsLogged(account.addr)
        });
    }, [])

    const logIn = () => {
        fcl.authenticate();
    }

    const logOut = () => {
        fcl.unauthenticate();
    }

    return (
        <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
            {isLogged ? (
                <div className="p-3">
                    <h3 className="text-2xl">{user.addr}</h3>
                    <button onClick={logOut}
                            className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                        Logout
                    </button>
                </div>
            ) : (
                <button onClick={logIn}
                        className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                    Login
                </button>
            )}
        </div>
    );
}

export default App;
```

## Step 6. Running the ReactJS dApp 

Run the npm-start command and open the page in http://localhost:3000/

## Step 7. Creating first smart contract

Create the Profile.cdc file in the fcl-dev-wallet/cadence/contract directory:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8sp3quiiwjmsudkvny98.png)

Add the smart contract to the configuration file of the fcl-dev-wallet/flow.json directory:

```json
{
  …
  "contracts": {
    "Profile": {
      "source": "./cadence/contracts/Profile.cdc"
      "aliases": {
        "emulator": "0xee82856bf20e2aa6"
     }
    },
    …
  },
  …
  "deployments": {
    "emulator": {
      "emulator-account": ["FUSD", "Profile"]
    }
  }
}
```
Deploy the Profile.cdc file to the local emulator:

`flow project deploy --update`

## Step 8. Creating first cadence script 

Extract data from the blockchain network:

```js
const getProfile = async () => {
        const [firstName, lastName, email] = await fcl.send([
            fcl.script`
            import Profile from 0xf8d6e0586b0a20c7
           
            pub fun main(): [String] {
              return [Profile.firstName, Profile.lastName, Profile.email]
            }
            `
        ]).then(fcl.decode)

        setProfile({ firstName, lastName, email })
    }
view raw
```

## Step 9. Creating first blockchain transaction

Create the blockchain transaction to modify the data in the blockchain network:

```js
const updateProfile = async () => {
        const txId = await fcl.send(
            [
                fcl.transaction`
                import Profile from 0xProfile
               
                transaction(newFirstName: String, newLastName: String, newEmail: String) {
               
                  prepare(signer: AuthAccount) {
                 
                  }
               
                  execute {
                    Profile.updateProfile(newFirstName: newFirstName, newLastName: newLastName, newEmail: newEmail)
                  }
                }
                `,// update profile transaction
                fcl.args([
                    fcl.arg(profile.firstName, t.String),
                    fcl.arg(profile.lastName, t.String),
                    fcl.arg(profile.email, t.String)
                ]), // parameters of the transaction
                fcl.proposer(fcl.authz), // The account that initiate this transaction
                fcl.payer(fcl.authz), // The account that pays the fee for this transaction (free on local emulator)
                fcl.authorizations([fcl.authz]), // A list of the accounts that are authorizing this transaction to mutate to their on-chain account state.
                fcl.limit(9999), // The maximum number of computational units that can be used to execute this transaction.
            ]
        ).then(fcl.decode);

        alert(`The transaction executed successfully`);
    }
```

## Step 10. Updating content

Add the cadence script and the blockchain transaction to the AppJS component and create a from to update the content (user profile):

```js
import * as fcl from "@onflow/fcl";
import * as t from "@onflow/types"

import './App.css';
import { useEffect, useState } from "react";

fcl
    .config()
    // Point App at Emulator REST API
    .put("accessNode.api", "http://localhost:8888")
    // Point FCL at dev-wallet (default port)
    .put("discovery.wallet", "http://localhost:8701/fcl/authn")
    .put("0xProfile", "0xf8d6e0586b0a20c7");

function App() {

    const [isLogged, setIsLogged] = useState(false);
    const [user, setUser] = useState();
    const [profile, setProfile] = useState();

    useEffect(() => {
        fcl.currentUser.subscribe((account) => {
            setUser(account);
            setIsLogged(account.addr)
            getProfile();
        });
    }, [])

    const getProfile = async () => {
        const [firstName, lastName, email] = await fcl.send([
            fcl.script`
            import Profile from 0xProfile
           
            pub fun main(): [String] {
              return [Profile.firstName, Profile.lastName, Profile.email]
            }
            `
        ]).then(fcl.decode)

        setProfile({ firstName, lastName, email })
    }

    const updateProfile = async (e) => {
        e.preventDefault();

        const txId = await fcl.send(
            [
                fcl.transaction`
                import Profile from 0xProfile
               
                transaction(newFirstName: String, newLastName: String, newEmail: String) {
               
                  prepare(signer: AuthAccount) {
                 
                  }
               
                  execute {
                    Profile.updateProfile(newFirstName: newFirstName, newLastName: newLastName, newEmail: newEmail)
                  }
                }
                `,// update profile transaction
                fcl.args([
                    fcl.arg(profile.firstName, t.String),
                    fcl.arg(profile.lastName, t.String),
                    fcl.arg(profile.email, t.String)
                ]), // parameters of the transaction
                fcl.proposer(fcl.authz), // The account that initiate this transaction
                fcl.payer(fcl.authz), // The account that pays the fee for this transaction (free on local emulator)
                fcl.authorizations([fcl.authz]), // A list of the accounts that are authorizing this transaction to mutate to their on-chain account state.
                fcl.limit(9999), // The maximum number of computational units that can be used to execute this transaction.
            ]
        ).then(fcl.decode);

        console.log(txId);
        alert(`The transaction executed successfully`);
    }

    const logIn = () => {
        fcl.authenticate();
    }

    const logOut = () => {
        fcl.unauthenticate();
    }

    const handleInputChange = (e) => {
        setProfile({ ...profile, [e.target.id]: e.target.value });
    }


    const profileBlock = profile ? (<div className="border-b-2 block md:flex">
        <div className="w-full p-8 bg-white shadow-md">
            <form onSubmit={updateProfile} autoComplete="off">
                <div className="pb-6">
                    <label htmlFor="firstName"
                          className="font-semibold text-gray-700 block pb-1">First Name</label>
                    <div className="flex">
                        <input id="firstName" required className="border-1 bg-gray-200 rounded-r px-4 py-2 w-full"
                              type="text" value={profile.firstName} onChange={handleInputChange}/>
                    </div>
                </div>
                <div className="pb-6">
                    <label htmlFor="lastName"
                          className="font-semibold text-gray-700 block pb-1">Last Name</label>
                    <div className="flex">
                        <input id="lastName" required className="border-1 bg-gray-200 rounded-r px-4 py-2 w-full"
                              type="text" value={profile.lastName} onChange={handleInputChange}/>
                    </div>
                </div>
                <div className="pb-6">
                    <label htmlFor="email"
                          className="font-semibold text-gray-700 block pb-1">Email</label>
                    <div className="flex">
                        <input id="email" autocomplete="nope" required
                              className="border-1 bg-gray-200 rounded-r px-4 py-2 w-full"
                              type="email" value={profile.email} onChange={handleInputChange}/>
                    </div>
                </div>
                <div>

                    <button type="submit"
                            className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
                        Update Profile
                    </button>
                </div>
            </form>
        </div>
    </div>) : '';

    return (
        <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
            {isLogged ? (
                <div className="p-3">
                    <span className="inline-block text-2xl mr-2">Account address: {user.addr}</span>
                    <button onClick={logOut}
                            className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                        Logout
                    </button>
                    {profileBlock}
                </div>
            ) : (
                <button onClick={logIn}
                        className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                    Login
                </button>
            )}
        </div>
    );
}

export default App;
```
Now you can test you first decentralized application.
__
There are around [4,000 decentralized applications](https://www.stateofthedapps.com/stats) being utilized in government, healthcare and even gambling. And the positive dynamics undoubtedly attest the feasibility and profitability of adopting blockchain solutions. When speaking about their market dominance, decentralized apps are unlikely to replace traditional apps. However, they are expected to get more momentum in the business environment.

**Here are some statistics to consider:**
- Over 199000 Bitcoin transactions are carried out in a single day
- 10 percent of the global population own cryptocurrencies
- 16 percent of Americans have invested in cryptocurrency
- The global Blockchain market is expected to reach $34 billion by 2026
In dApps, personal and business data is stored in separate immutable blocks on the blockchain environment. This means, sensitive data is protected from exploitation, one of the most serious issues, which might be faced by both young startups and mature international corporations.