Frontend Integration

React Integration Guide

React hooks, components, and examples for seamless Flow blockchain integration. Connect wallets, execute transactions, and query blockchain state with ease.

React Hooks
Custom hooks for wallet connection, authentication, and blockchain interactions

useFlowWallet

Connect and manage Flow wallet connections

// hooks/useFlowWallet.ts
import { useState, useEffect, useCallback } from 'react'
import * as fcl from '@onflow/fcl'

export interface FlowUser {
  addr: string | null
  cid: string | null
  loggedIn: boolean
  services: any[]
}

export function useFlowWallet() {
  const [user, setUser] = useState<FlowUser>({
    addr: null,
    cid: null,
    loggedIn: false,
    services: []
  })
  const [isLoading, setIsLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    // Configure FCL
    fcl.config({
      'accessNode.api': process.env.NEXT_PUBLIC_FLOW_ACCESS_NODE || 'https://rest-testnet.onflow.org',
      'discovery.wallet': process.env.NEXT_PUBLIC_FLOW_WALLET_DISCOVERY || 'https://fcl-discovery.onflow.org/testnet/authn',
      'app.detail.title': 'FlowDevKit App',
      'app.detail.icon': 'https://flowdevkit.com/logo.png',
    })

    // Subscribe to user changes
    const unsubscribe = fcl.currentUser.subscribe(setUser)
    return () => unsubscribe()
  }, [])

  const login = useCallback(async () => {
    setIsLoading(true)
    setError(null)
    try {
      await fcl.authenticate()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to authenticate')
    } finally {
      setIsLoading(false)
    }
  }, [])

  const logout = useCallback(async () => {
    setIsLoading(true)
    try {
      await fcl.unauthenticate()
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to logout')
    } finally {
      setIsLoading(false)
    }
  }, [])

  const signMessage = useCallback(async (message: string) => {
    if (!user.loggedIn) {
      throw new Error('User not authenticated')
    }
    
    try {
      const signature = await fcl.currentUser.signUserMessage(message)
      return signature
    } catch (err) {
      throw new Error('Failed to sign message')
    }
  }, [user.loggedIn])

  return {
    user,
    isLoading,
    error,
    login,
    logout,
    signMessage,
    isAuthenticated: user.loggedIn
  }
}
Key Features
• TypeScript support with full type safety
• Automatic error handling and loading states
• React hooks pattern for easy integration
• Configurable options and callbacks
Usage Example
// Import and use in your component
import { useFlowWallet } from '@/components/useFlowWallet'

export function MyApp() {
  return (
    <div>
      <useFlowWallet 
        contractAddress="0x01"
        contractName="FlowDevKitNFT"
      />
    </div>
  )
}
React Components
Pre-built UI components for common Flow blockchain interactions

WalletConnect

Wallet connection button with status display

// components/WalletConnect.tsx
'use client'

import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Wallet, LogOut, Loader2 } from 'lucide-react'
import { useFlowWallet } from '@/hooks/useFlowWallet'

interface WalletConnectProps {
  className?: string
  showDetails?: boolean
}

export function WalletConnect({ className, showDetails = false }: WalletConnectProps) {
  const { user, isLoading, error, login, logout, isAuthenticated } = useFlowWallet()

  if (showDetails && isAuthenticated) {
    return (
      <Card className={className}>
        <CardHeader className="pb-3">
          <CardTitle className="text-base flex items-center gap-2">
            <Wallet className="h-4 w-4" />
            Connected Wallet
          </CardTitle>
          <CardDescription>
            Your Flow wallet is connected and ready to use
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-3">
          <div className="flex items-center justify-between">
            <span className="text-sm text-muted-foreground">Address:</span>
            <Badge variant="secondary" className="font-mono text-xs">
              {user.addr?.slice(0, 8)}...{user.addr?.slice(-6)}
            </Badge>
          </div>
          <div className="flex items-center justify-between">
            <span className="text-sm text-muted-foreground">Status:</span>
            <Badge variant="default">Connected</Badge>
          </div>
          <Button 
            variant="outline" 
            size="sm" 
            onClick={logout}
            disabled={isLoading}
            className="w-full bg-transparent"
          >
            {isLoading ? (
              <Loader2 className="h-4 w-4 mr-2 animate-spin" />
            ) : (
              <LogOut className="h-4 w-4 mr-2" />
            )}
            Disconnect
          </Button>
        </CardContent>
      </Card>
    )
  }

  return (
    <Button
      onClick={isAuthenticated ? logout : login}
      disabled={isLoading}
      className={className}
      variant={isAuthenticated ? "outline" : "default"}
    >
      {isLoading ? (
        <Loader2 className="h-4 w-4 mr-2 animate-spin" />
      ) : (
        <Wallet className="h-4 w-4 mr-2" />
      )}
      {isAuthenticated ? 'Disconnect' : 'Connect Wallet'}
    </Button>
  )
}
Key Features
• Pre-built UI components with shadcn/ui
• Responsive design and accessibility
• Customizable styling and behavior
• Real-time data updates
Usage Example
// Import and use in your component
import { WalletConnect } from '@/components/WalletConnect'

export function MyApp() {
  return (
    <div>
      <WalletConnect 
        contractAddress="0x01"
        contractName="FlowDevKitNFT"
      />
    </div>
  )
}
Integration Examples
Complete examples showing how to integrate Flow into your React applications

Complete App Setup

Full application setup with FCL configuration

// app/layout.tsx
import { FlowProvider } from '@/components/FlowProvider'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <FlowProvider>
          {children}
        </FlowProvider>
      </body>
    </html>
  )
}

// components/FlowProvider.tsx
'use client'

import { useEffect } from 'react'
import * as fcl from '@onflow/fcl'

interface FlowProviderProps {
  children: React.ReactNode
}

export function FlowProvider({ children }: FlowProviderProps) {
  useEffect(() => {
    fcl.config({
      'accessNode.api': process.env.NEXT_PUBLIC_FLOW_ACCESS_NODE || 'https://rest-testnet.onflow.org',
      'discovery.wallet': process.env.NEXT_PUBLIC_FLOW_WALLET_DISCOVERY || 'https://fcl-discovery.onflow.org/testnet/authn',
      'app.detail.title': 'FlowDevKit App',
      'app.detail.icon': 'https://flowdevkit.com/logo.png',
      'service.OpenID.scopes': 'email email_verified name zoneinfo',
    })
  }, [])

  return <>{children}</>
}
Key Features
• Complete application examples
• Production-ready code patterns
• Error handling and edge cases
• Performance optimizations
Usage Example
// Import and use in your component
import { Complete App Setup } from '@/components/Complete App Setup'

export function MyApp() {
  return (
    <div>
      <Complete App Setup 
        contractAddress="0x01"
        contractName="FlowDevKitNFT"
      />
    </div>
  )
}
Installation & Setup
Get started with Flow integration in your React app

1. Install Dependencies

# Install Flow Client Library
npm install @onflow/fcl @onflow/types

# Install UI components (optional)
npm install @radix-ui/react-* class-variance-authority

2. Environment Variables

# .env.local
NEXT_PUBLIC_FLOW_ACCESS_NODE=https://rest-testnet.onflow.org
NEXT_PUBLIC_FLOW_WALLET_DISCOVERY=https://fcl-discovery.onflow.org/testnet/authn

3. Configure FCL

// lib/flow.ts
import * as fcl from '@onflow/fcl'

fcl.config({
  'accessNode.api': process.env.NEXT_PUBLIC_FLOW_ACCESS_NODE,
  'discovery.wallet': process.env.NEXT_PUBLIC_FLOW_WALLET_DISCOVERY,
  'app.detail.title': 'Your App Name',
  'app.detail.icon': 'https://yourapp.com/logo.png',
})

4. Add to Your App

// app/page.tsx
import { WalletConnect } from '@/components/WalletConnect'
import { NFTBalance } from '@/components/NFTBalance'

export default function Home() {
  return (
    <div className="space-y-6">
      <WalletConnect showDetails />
      <NFTBalance 
        contractAddress="0x01" 
        contractName="FlowDevKitNFT" 
      />
    </div>
  )
}