Skip to Content
Welcome to RitoSwap's documentation!

NFTScreen

The NFTScreen component serves as the visual centerpiece of the minting interface, dynamically displaying the current NFT ownership state through animated graphics. This component masterfully handles the complex challenge of smoothly transitioning between different visual states while maintaining visual continuity during wallet switches and data loading. Through its sophisticated state management and hardcoded SVG approach, it delivers performant, visually appealing NFT representation without the overhead of external image loading.

Component Architecture

NFTScreen implements a multi-layered state system that separates display logic from data fetching, enabling smooth visual transitions even during complex blockchain operations. The component uses a combination of local state management for transition control and store subscriptions for data updates, creating a responsive yet stable visual experience that never shows loading states or flickers during updates.

Visual State Machine

The component manages four distinct visual states that represent the user’s relationship with the NFT system:

Visual StateDisplayTrigger Conditions
Lock IconPadlock image (150x150)User not connected to wallet
Default KeyWhite key on dark backgroundConnected but no NFT owned
User KeyColored key with custom backgroundNFT owned with color data
LoadingEmpty (no visual)Initial component mount or wallet connecting

Interactive Demo

Locked

Hardcoded SVG Strategy

NFTScreen takes a unique approach by hardcoding the key SVG directly in the component rather than fetching it from the blockchain or external sources:

<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg"> <circle cx="60" cy="50" r="20" fill="none" stroke="currentColor" strokeWidth={10} /> <rect x="80" y="45" width="100" height="10" rx={5} fill="currentColor" /> <path d="M145 30 A5 5 0 0 1 150 35 V46 H140 V35 A5 5 0 0 1 145 30 Z" fill="currentColor" /> <path d="M165 36 A5 5 0 0 1 170 41 V46 H160 V41 A5 5 0 0 1 165 36 Z" fill="currentColor" /> </svg>

This approach provides several benefits: elimination of network requests for images, instant rendering without loading delays, easy color manipulation through CSS, and consistent display across all environments.

⚠️

The hardcoded SVG approach works perfectly for Colored Keys where the image structure is known and constant. For other NFT collections with varying images, developers would need to implement dynamic image loading or maintain a library of hardcoded assets.

Props and Interface

NFTScreen requires no props, deriving all necessary data from hooks and stores:

export default function NFTScreen() { const { isConnected, isConnecting } = useAccount() const { hasNFT, backgroundColor, keyColor, tokenId, isSwitchingAccount, previousData, } = useNFTStore() }

This zero-configuration design ensures consistency and simplifies integration.

State Transition System

The component implements a sophisticated debounced state transition system to prevent visual flashing:

State Management Variables

const [isInitialized, setIsInitialized] = useState(false) const [displayState, setDisplayState] = useState<'lock' | 'default-key' | 'user-key' | 'loading'>('loading') const [isStable, setIsStable] = useState(false) const stateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)

Each variable serves a specific purpose in managing smooth transitions:

  • isInitialized - Prevents rendering until wagmi connection state stabilizes
  • displayState - Current visual state being rendered
  • isStable - Marks when component has reached a stable state for CSS animations
  • stateTimeoutRef - Manages debounce timers for state changes

Transition Debouncing

The component uses a 200ms debounce for most state transitions:

stateTimeoutRef.current = setTimeout(() => { if (targetState !== displayState) { setDisplayState(targetState) } }, 200) // Small delay to prevent rapid flashing

However, transitions from the initial loading state happen immediately to ensure quick first render.

Initial Connection Stabilization

The component implements a 300ms initialization delay to allow wagmi to restore any previous wallet connections:

useEffect(() => { const timer = setTimeout(() => { setIsInitialized(true) }, 300) // Give wagmi time to restore connection return () => clearTimeout(timer) }, [])

This critical delay prevents the component from briefly flashing the lock icon when the page loads with an already-connected wallet. Without this delay, users would see: loading → lock → key, instead of the desired: loading → key.

Account Switching Preservation

One of NFTScreen’s most sophisticated features is its handling of account switches:

const displayData = isSwitchingAccount && previousData ? { backgroundColor: previousData.backgroundColor, keyColor: previousData.keyColor, tokenId: previousData.tokenId, } : { backgroundColor, keyColor, tokenId }

During account switches, the component continues displaying the previous account’s NFT data, preventing the jarring experience of briefly showing “no NFT” while new data loads.

Color Application System

The component applies colors dynamically based on ownership state:

Background Color

const wrapperStyle = displayState === 'user-key' ? { backgroundColor: displayData.backgroundColor ?? 'rgba(0,0,0,0.3)', transition: isSwitchingAccount ? 'none' : 'background-color 1s ease-in-out', } : { backgroundColor: 'rgba(0,0,0,0.3)' }

Transitions are disabled during account switches to prevent color flashing.

Key Color

const svgColor = displayState === 'user-key' ? displayData.keyColor ?? 'white' : 'white'

The SVG uses currentColor, allowing the color to be controlled through CSS.

Token ID Display

The component displays the token ID above the visual representation:

<div className={styles.tokenIdText}> {displayTokenId != null ? `Key #${displayTokenId}` : ''} </div>

The empty string fallback ensures consistent spacing even when no token is owned.

CSS Animation Strategy

NFTScreen uses sophisticated CSS animations for smooth transitions:

.wrapper { opacity: 1; transform: scale(1); transition: all 0.5s ease-in-out; } .wrapper.stable { opacity: 1; transform: scale(1); transition: all 0.5s ease-in-out; /* No animation - relies on transitions only */ } .wrapper.switching { opacity: 0.3; transform: scale(0.98); }

The multi-class approach allows different transition behaviors based on component state.

Dynamic Class Application

The component combines multiple CSS classes dynamically based on state:

<div className={[ styles.wrapper, isSwitchingAccount && styles.switching, isStable && styles.stable, ] .filter(Boolean) .join(' ')} >

This pattern ensures only relevant CSS classes are applied, with filter(Boolean) removing any false values before joining.

Performance Optimizations

The component implements several performance optimizations:

Debounced Updates - The 200ms debounce prevents rapid visual changes during blockchain query resolution.

CSS-Only Animations - All transitions use GPU-accelerated CSS properties for smooth 60fps animations.

Conditional Rendering - The loading state renders nothing, preventing unnecessary DOM manipulation.

Ref-Based Timers - Using refs for timeouts prevents memory leaks and ensures proper cleanup.

Responsive Design

NFTScreen adapts its layout for mobile devices:

@media (max-width: 768px) { .wrapper { min-height: 400px; /* Reduced from 550px */ } .container { max-width: 350px; /* Reduced from 500px */ } .tokenIdText { font-size: 1rem; /* Reduced from 1.2rem */ } }

The aspect ratio remains 1:1 to maintain visual consistency across screen sizes.

Integration with Store

The component deeply integrates with the NFT store for state management:

Store FieldUsageFallback Behavior
hasNFTDetermines key vs lock displayShows default key if false
backgroundColorNFT background colorDark transparent if null
keyColorSVG key colorWhite if null
tokenIdDisplay text above visualEmpty string if null
isSwitchingAccountTriggers preservation modeNormal display if false
previousDataSource for switch preservationCurrent data if null

Error Handling

While NFTScreen doesn’t explicitly handle errors, it’s designed to degrade gracefully:

  • Missing color data falls back to default white key
  • Failed image loads don’t occur due to hardcoded SVG
  • Null token IDs simply don’t display
  • Unexpected states would continue showing the current visual state

Test Identifiers

The component provides several data-testid attributes for reliable test selection:

Test IDElementWhen Present
lock-iconLock icon wrapperWhen user is not connected
key-wrapperKey background wrapperWhen showing any key state
key-svgSVG key elementWhen showing any key state

These identifiers enable precise component selection in integration and end-to-end tests.

Testing Strategies

Testing NFTScreen requires careful state simulation:

describe('NFTScreen', () => { it('shows custom colored key when user has NFT', async () => { mockUseNFTStore({ hasNFT: true, backgroundColor: '#FF0000', keyColor: '#00FF00', tokenId: 42, }) render(<NFTScreen />) await waitFor(() => { expect(screen.getByText('Key #42')).toBeInTheDocument() const wrapper = screen.getByTestId('key-wrapper') expect(wrapper).toHaveStyle({ backgroundColor: '#FF0000' }) }) }) })

Customization Guide

To adapt NFTScreen for different NFT collections:

Dynamic Image Loading

Replace the hardcoded SVG with dynamic image loading:

{displayState === 'user-key' && tokenURI ? ( <img src={tokenURI} alt={`NFT #${tokenId}`} /> ) : ( // Default visualization )}

Alternative Visualizations

The SVG structure can be modified to show different default states:

// Example: Badge instead of key <svg viewBox="0 0 100 100"> <circle cx="50" cy="50" r="45" fill="currentColor" /> <text x="50" y="50" textAnchor="middle">NFT</text> </svg>

Animation Variations

Transition effects can be customized through CSS:

/* Example: Rotation effect */ .wrapper.switching { transform: scale(0.98) rotate(5deg); }

Common Patterns and Anti-Patterns

State Debouncing - Always debounce rapid state changes to prevent visual instability.

Fallback Values - Provide sensible defaults for all nullable data to ensure consistent display.

Transition Control - Use CSS classes to control animation behavior based on component state.

Anti-Patterns to Avoid

Direct DOM Manipulation - Let React handle all DOM updates through state changes.

Synchronous State Updates - Always use timeouts or effects for state transitions.

Loading Spinners - Avoid showing loading states; maintain current visual until new data arrives.

Accessibility Considerations

NFTScreen implements several accessibility features:

Alternative Text - The lock image includes proper alt text for screen readers.

Semantic Structure - Token ID text provides context for the visual display.

Color Contrast - Default colors ensure sufficient contrast for visibility.

Troubleshooting Guide

IssueLikely CauseSolution
Key flickers during loadMissing initialization delayEnsure 300ms initialization timer
Colors don’t animateTransition disabledCheck isSwitchingAccount state
Wrong display during switchpreviousData not setVerify store switch logic
Lock shows with NFTConnection state issueCheck wagmi isConnected value

Summary

NFTScreen exemplifies sophisticated state management in React components dealing with asynchronous blockchain data. Through its innovative use of hardcoded SVGs, debounced state transitions, and account switch preservation, it delivers a smooth, professional visual experience that masks the complexity of underlying blockchain operations. The component’s zero-configuration design, graceful fallbacks, and performance optimizations make it a robust solution for NFT visualization. While currently optimized for Colored Keys with known visual structure, its architecture provides clear patterns for adaptation to other NFT collections requiring dynamic image loading or alternative visualizations.