Skip to main content

Performance Guide

Optimize your QwickApps React Framework applications for maximum performance with data binding, component optimization, and caching strategies.

Overview

QwickApps React Framework is designed for performance out of the box, but understanding key optimization techniques will help you build faster, more responsive applications.

Data Binding Performance

Caching Strategies

Use CachedDataProvider for automatic performance optimization:

import { CachedDataProvider, JsonDataProvider } from '@qwickapps/schema';

const jsonProvider = new JsonDataProvider({ data: cmsData });
const cachedProvider = new CachedDataProvider(jsonProvider, {
maxSize: 100, // Cache up to 100 items
defaultTTL: 300000, // 5-minute cache TTL
enableMetrics: true // Track cache performance
});

Cache Hit Monitoring

Monitor cache performance in development:

const cacheMetrics = cachedProvider.getMetrics();
console.log('Cache hit ratio:', cacheMetrics.hitRatio);
console.log('Total requests:', cacheMetrics.totalRequests);
console.log('Cache size:', cacheMetrics.currentSize);

Optimized Data Sources

Structure data sources for efficient lookup:

// ✅ Efficient - specific paths
"company.header.title"
"pages.home.hero.subtitle"
"features.responsive.description"

// ❌ Inefficient - overly nested
"global.data.content.pages.home.sections.hero.blocks.title.text"

Component Optimization

Lazy Loading

Load heavy components on demand:

import { lazy, Suspense } from 'react';

const HeavyFeatureGrid = lazy(() => import('./HeavyFeatureGrid'));

function OptimizedSection() {
return (
<Section>
<Suspense fallback={<LoadingSpinner />}>
<HeavyFeatureGrid dataSource="features.grid" />
</Suspense>
</Section>
);
}

Memoization

Use React.memo for expensive components:

import { memo } from 'react';

const ExpensiveCard = memo(function ExpensiveCard({ data }) {
// Expensive calculations or rendering
return <div>{/* Complex UI */}</div>;
});

// Usage with data binding
<ExpensiveCard dataSource="cards.featured" />

Virtual Scrolling

For large lists, use virtual scrolling patterns:

import { FixedSizeList as List } from 'react-window';

function VirtualizedCardList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>
<ProductCard dataSource={`products.${items[index].id}`} />
</div>
);

return (
<List
height={600}
itemCount={items.length}
itemSize={200}
>
{Row}
</List>
);
}

Image Optimization

Responsive Images

Optimize images for different screen sizes:

<CoverImageHeader
title="Hero Section"
backgroundImage={{
mobile: "/images/hero-400w.webp",
tablet: "/images/hero-800w.webp",
desktop: "/images/hero-1200w.webp",
large: "/images/hero-1600w.webp"
}}
loading="eager" // Above fold
/>

Lazy Loading Images

Load images below the fold lazily:

<FeatureCard
feature={{
title: "Feature Title",
image: "/images/feature.webp"
}}
loading="lazy" // Below fold
placeholder="/images/feature-placeholder.webp"
/>

WebP Format

Use modern image formats with fallbacks:

<picture>
<source srcSet="/image.webp" type="image/webp" />
<source srcSet="/image.jpg" type="image/jpeg" />
<img src="/image.jpg" alt="Description" />
</picture>

Bundle Optimization

Tree Shaking

Import only what you need:

// ✅ Efficient - tree-shakeable imports
import { Button, Section } from '@qwickapps/react-framework';

// ❌ Inefficient - imports entire library
import * as QwickApps from '@qwickapps/react-framework';

Code Splitting

Split code by route or feature:

// Route-based splitting
const HomePage = lazy(() => import('./pages/HomePage'));
const AboutPage = lazy(() => import('./pages/AboutPage'));

// Feature-based splitting
const AdminDashboard = lazy(() => import('./features/AdminDashboard'));

Dynamic Imports

Load components based on conditions:

async function loadComponent(componentType: string) {
switch (componentType) {
case 'chart':
return (await import('./ChartComponent')).default;
case 'map':
return (await import('./MapComponent')).default;
default:
return (await import('./DefaultComponent')).default;
}
}

Theme Performance

CSS Variables Optimization

Use CSS variables efficiently:

/* ✅ Efficient - minimal custom properties */
.component {
color: var(--theme-primary);
background: var(--theme-surface);
}

/* ❌ Inefficient - excessive custom properties */
.component {
color: var(--component-text-primary-color-light-mode-default);
background: var(--component-background-surface-color-light-mode-default);
}

Theme Switching Optimization

Optimize theme switching performance:

// Use CSS transitions for smooth theme changes
.qwick-app {
transition: background-color 0.2s ease, color 0.2s ease;
}

// Avoid JavaScript-heavy theme switching
const { setCurrentTheme } = useTheme();
setCurrentTheme('dark'); // Efficient - uses CSS variables

Memory Management

Data Provider Cleanup

Clean up data providers when components unmount:

useEffect(() => {
const provider = new JsonDataProvider({ data });

return () => {
provider.cleanup?.(); // Clean up resources
};
}, []);

Cache Size Limits

Set appropriate cache limits:

const cachedProvider = new CachedDataProvider(provider, {
maxSize: 50, // Reasonable limit for mobile
maxMemoryMB: 10, // Memory-based limits
cleanupInterval: 30000 // Regular cleanup
});

Performance Monitoring

Runtime Performance

Monitor component performance in development:

import { Profiler } from 'react';

function onRenderCallback(id, phase, actualDuration) {
console.log(`${id} (${phase}) took ${actualDuration}ms`);
}

<Profiler id="FeatureGrid" onRender={onRenderCallback}>
<FeatureGrid dataSource="features.main" />
</Profiler>

Data Binding Metrics

Track data binding performance:

const bindingMetrics = useDataBinding.getMetrics?.();
console.log('Average binding time:', bindingMetrics.averageTime);
console.log('Cache hit ratio:', bindingMetrics.cacheHitRatio);

Bundle Analysis

Analyze bundle size regularly:

# Analyze bundle composition
npm run build -- --analyze

# Check for unused dependencies
npx depcheck

# Measure bundle size impact
npx bundlephobia <package-name>

Performance Checklist

✅ Data Binding

  • Use CachedDataProvider for frequently accessed data
  • Structure data sources for efficient lookup
  • Monitor cache hit ratios in development
  • Set appropriate TTL values for different content types

✅ Components

  • Lazy load components below the fold
  • Use React.memo for expensive components
  • Implement virtual scrolling for large lists
  • Optimize re-render patterns with proper dependencies

✅ Images

  • Use responsive image patterns
  • Implement lazy loading for below-fold images
  • Use modern formats (WebP) with fallbacks
  • Optimize image sizes for different breakpoints

✅ Bundle

  • Use tree-shakeable imports
  • Implement code splitting by route/feature
  • Analyze bundle size regularly
  • Remove unused dependencies

✅ Theme

  • Use efficient CSS variable patterns
  • Optimize theme switching with CSS transitions
  • Minimize custom property usage
  • Cache theme calculations

Performance Targets

Loading Performance

  • First Contentful Paint: < 1.5s
  • Largest Contentful Paint: < 2.5s
  • Time to Interactive: < 3.5s
  • Cumulative Layout Shift: < 0.1

Runtime Performance

  • Component Mount: < 16ms (60 FPS)
  • Data Binding Resolution: < 5ms average
  • Theme Switching: < 100ms
  • Cache Hit Ratio: > 85%

Bundle Size Targets

  • Initial Bundle: < 200KB gzipped
  • Route Chunks: < 100KB gzipped each
  • Vendor Chunks: < 150KB gzipped
  • CSS Bundle: < 50KB gzipped

Troubleshooting

Common Performance Issues

Slow Data Binding

// Check cache configuration
const metrics = cachedProvider.getMetrics();
if (metrics.hitRatio < 0.8) {
// Increase cache size or TTL
}

Large Bundle Size

# Analyze what's causing bundle bloat
npm run build -- --analyze
npx webpack-bundle-analyzer build/static/js/*.js

Memory Leaks

// Ensure proper cleanup in useEffect
useEffect(() => {
const subscription = dataProvider.subscribe(callback);
return () => subscription.unsubscribe();
}, []);

What's Next?