Create a Web App on Flow
This guide is a simple walkthrough to get started building a web3 app using the Flow Client Library (FCL).
If you are looking for a scalfolds, check out scaffolds available in the Flow CLI.
This simple guide uses the "Hello World" scaffold, it is meant to provide all the code needed to get a web application up and running.
Introduction​
FCL (aka Flow Client Library) wraps the logic needed to communicate with the Flow blockchain. It's a npm package, More Information
This guide assumes a good understanding of React. The concepts are easy to understand and apply to other libraries and framework. A strong understanding of Cadence (Flow's smart contract language) is not required. More information on Cadence, learning the Cadence language.
FCL concepts covered:​
- Installation
- Configuration
- Authenticate a user
- Deploy contracts
- Query the Blockchain
- Mutate the Blockchain
For more help, Discord. See links at the end of this article for diving deeper into building on Flow.
Installation​
Make sure you have Flow CLI installed. installation instructions.
Configuration​
Setting up Flow​
Using the Flow CLI scaffold, create a basic hello world web project with Web Scaffolds
-> [5] FCL Web Dapp
. This will create a new flow.json
file in the hello-world
folder. This file will contain the Flow configuration for your project.
_10flow setup hello-world --scaffold_10# select scaffold 5_10cd hello-world_10npm install_10# run the app in a later step
We don't recommend keeping private keys in your flow.json
, notice that Flow CLI already moved the emulator private key to a emulator.key
file and point to it using the key/location pattern. This file should be added to your .gitignore
file, so it won't be committed to your repository.
We won't be using emulator and running contracts locally in this quickstart, but FCL will complain if it finds private keys in your flow.json
file.
Your flow.json
file should look like this:
_16{_16 "networks": {_16 "emulator": "127.0.0.1:3569",_16 "mainnet": "access.mainnet.nodes.onflow.org:9000",_16 "testnet": "access.devnet.nodes.onflow.org:9000"_16 },_16 "accounts": {_16 "emulator-account": {_16 "address": "f8d6e0586b0a20c7",_16 "key": {_16 "type": "file",_16 "location": "./emulator.key"_16 }_16 }_16 }_16}
The flow.json
file is used to keep track of deployed contracts and accounts. More Information
Configuring FCL​
Next, notice @onflow/fcl
has been added to the package.json
and the web application is ready to be run.
There are a lot of benefits to getting familiar with existing Flow CLI scaffolds. For example the hello-world
scaffold already has fcl configuration settings to run on local emulator.
The hello-world
web application comes with convenience npm commands to facilitate a quick start. The following command will preform:
- Start emulator
- Start dev wallet
- Start web app
Emulator is a local blockchain More Information. Emulator has all the features as testnet and mainnet blockchains
_10npm run dev:local
Now that your app is running. FCL loads the configuration in config/fcl.ts
This file contains configuration information for FCL, such as what Access Node and wallet discovery endpoint and which network to use (e.g. testnet or a local emulator).
accessNode.api
key specifies the address of a Flow access node. There are publically available access nodes, but have to rate limit. Alternatively, applications might want to run an Observer node Run a Node.discovery.wallet
is an address that points to a service that lists FCL compatible wallets. Flow's FCL Discovery service is a service that FCL wallet providers can be added to, and be made 'discoverable' to any application that uses thediscovery.wallet
endpoint.
Also, notice that package.json
uses NEXT_PUBLIC_FLOW_NETWORK=local
for dev
command, this is used to set the network in config/fcl.ts
.
Learn more about configuring Discovery or setting configuration values.
The main Next.js app component is located in pages/_app.tsx
. It should import the config file config/fcl.ts
already and should look like this:
_15import '../styles/globals.css'_15import DefaultLayout from '../layouts/DefaultLayout'_15_15// Import FCL config_15import '../config/fcl'_15_15function MyApp({ Component, pageProps }) {_15 return (_15 <DefaultLayout>_15 <Component {...pageProps} />_15 </DefaultLayout>_15 )_15}_15_15export default MyApp
The main page for the Next.js app is located in pages/index.tsx
. It should contain some basic UI and should look like this:
_35import Head from 'next/head'_35import styles from '../styles/Home.module.css'_35import Links from '../components/Links'_35import Container from '../components/Container'_35import useCurrentUser from '../hooks/useCurrentUser'_35_35export default function Home() {_35 const { loggedIn } = useCurrentUser()_35_35 return (_35 <div className={styles.container}>_35_35 <Head>_35 <title>FCL Next Scaffold</title>_35 <meta name="description" content="FCL Next Scaffold for the Flow Blockchain" />_35 <link rel="icon" href="/favicon.ico" />_35 </Head>_35_35 <main className={styles.main}>_35 <h1 className={styles.title}>_35 <a href="https://developers.flow.com/tools/fcl-js">FCL</a> Next Scaffold_35 </h1>_35_35 <p className={styles.description}>_35 For the Flow Blockchain_35 </p>_35_35 {loggedIn && <Container />}_35_35 <Links />_35_35 </main>_35 </div>_35 )_35}
Now we're ready to start talking to Flow!
The web app will run, but there are no contracts deployed to local emulator. This is a step in Query the Blockchain section.
Authenticate a User​
Note: in the code above useCurrentUser
is used to determine if there is a logged in user.
There are two methods to allow the user to login. fcl.logIn()
or fcl.authenticate()
More Information on, authenticate
In components/Navbar.tsx
a button wires up the authentication method fcl.authenticate()
. It is used to bring up the list of supported wallets. See below
Once authenticated, FCL uses a hook const user = useCurrentUser()
to get the user data, when user is signed in user.loggedIn
flag is true
. For more information on the currentUser
, read more here.
_33import Head from 'next/head'_33import * as fcl from '@onflow/fcl'_33import useCurrentUser from '../hooks/useCurrentUser'_33import navbarStyles from '../styles/Navbar.module.css'_33import elementStyles from '../styles/Elements.module.css'_33_33export default function Navbar() {_33 const user = useCurrentUser()_33_33 return (_33 <div className={navbarStyles.navbar}>_33 {!user.loggedIn && _33 <button _33 onClick={fcl.authenticate} _33 className={elementStyles.button}>_33 Log In With Wallet_33 </button>_33 }_33 {user.loggedIn && _33 (_33 <>_33 <div className={navbarStyles.address}>{ user?.addr }</div>_33 <button _33 onClick={fcl.unauthenticate} _33 className={elementStyles.button}>_33 Log Out_33 </button>_33 </>_33 )_33 }_33 </div>_33 )_33}
You should now be able to log in or sign up users and unauthenticate them. Upon logging in or signing up your users will see a popup where they can choose between wallet providers. Choose the dev wallet
to use the same account that deployed the HelloWorld
contract, this is needed for mutation. Upon completing authentication, you'll see the component change and the user's wallet address appear on the screen if you've completed this properly.
More on wallets, Flow Core wallet is a Reference Flow wallet.
Deploy contracts​
Hello World scaffold does come with a Cadence contract. You will notice HelloWorld.cdc
has been deployed when running npm run dev:local
. Look at hello-world package.json
to see the commands that get run, flow dev
deploys contracts to the emulator.
In the flow.json
make sure the emulator endpoint is correct. Look at the terminal the emulator is running,
- Make sure the emulator is using the same port as
gRPC
and - The
deployment
section offlow.json
should look something like this:
_12 ..._12 "networks": {_12 "emulator": "127.0.0.1:3569",_12 ..._12 },_12 "deployments": {_12 "emulator": {_12 "default": [_12 "HelloWorld"_12 ]_12 } _12}
Verify that flow.json
updates with HelloWorld contract information, contracts
has the HelloWorld
contract and deployments
shows that HelloWorld
has been deployed.
_30{_30 "contracts": {_30 "HelloWorld": "cadence/contracts/HelloWorld.cdc"_30 },_30 "networks": {_30 "emulator": "127.0.0.1:3569",_30 "mainnet": "access.mainnet.nodes.onflow.org:9000",_30 "testnet": "access.devnet.nodes.onflow.org:9000"_30 },_30 "accounts": {_30 "default": {_30 "address": "01cf0e2f2f715450",_30 "key": "..."_30 },_30 "emulator-account": {_30 "address": "f8d6e0586b0a20c7",_30 "key": {_30 "type": "file",_30 "location": "./emulator.key"_30 }_30 }_30 },_30 "deployments": {_30 "emulator": {_30 "default": [_30 "HelloWorld"_30 ]_30 }_30 }_30}
For more information on deployments check Flow CLI documentation
Query the Blockchain​
Now that all pieces are in place. UI can query HelloWorld
contract.
The script that queries the Hello World contract is located hello-world/cadence/scripts/ReadHelloWorld.cdc
_10import "HelloWorld"_10_10pub fun main(): String {_10 return HelloWorld.greeting_10}
In components/Container.tsx
file, fcl.query
is used to set the Cadence script and query the contract.
_10_10 const queryChain = async () => {_10 const res = await fcl.query({_10 cadence: ReadHelloWorld_10 })_10_10 setChainGreeting(res)_10 }
It is that simple!
Mutate the Blockchain​
Update the HelloWorld
contract greeting. Notice that Greeting gets changed when the transaction gets processed.
In components/Container.tsx
file, the mutateGreeting
method fcl.mutate
sends UpdateHelloWorld
cadence which triggers a transaction that the user signs.
_14 const mutateGreeting = async (event) => {_14 event.preventDefault()_14_14 if (!userGreetingInput.length) {_14 throw new Error('Please add a new greeting string.')_14 }_14_14 const transactionId = await fcl.mutate({_14 cadence: UpdateHelloWorld,_14 args: (arg, t) => [arg(userGreetingInput, t.String)],_14 })_14_14 setLastTransactionId(transactionId)_14 }
More information​
That's it! You now have Flow app that uses auth, query and mutate the chain. This is just the beginning. There is so much more to know. Next steps:
Cadence
FCL Scaffolds
Full Stack NFT Marketplace Example
More FCL