Back to QuantaJS Blog

Wednesday, August 27, 2025

Persistence in Real-World Projects: A Practical Guide

Cover image for Persistence in Real-World Projects: A Practical Guide

Persistence in Real-World Projects: A Practical Guide

Ever wondered how your favorite apps remember your preferences, shopping cart items, or form data even after you close the browser? That's persistence in action! Today, we'll explore how QuantaJS makes this magic happen with real-world examples you can actually try.

What is Persistence?

Persistence is the ability to save and restore your application's state automatically. Think of it like a smart memory system that remembers everything important about your app, even when the user refreshes the page or closes the browser.

Real-World Scenarios

Let's look at some everyday situations where persistence makes a huge difference:

1. User Preferences Store

Imagine you're building a productivity app. Users want their theme, language, and notification settings to persist across sessions.

import { createStore, LocalStorageAdapter } from '@quantajs/core';

const userPreferencesStore = createStore('user-preferences', {
  state: () => ({
    theme: 'light',
    language: 'en',
    notifications: true,
    fontSize: 'medium'
  }),
  actions: {
    updateTheme(theme) {
      this.theme = theme;
    },
    updateLanguage(lang) {
      this.language = lang;
    },
    toggleNotifications() {
      this.notifications = !this.notifications;
    }
  },
  persist: {
    adapter: new LocalStorageAdapter('user-preferences'),
    debounceMs: 300
  }
});

Try it yourself: Change the theme below and refresh the page!

2. Shopping Cart Persistence

E-commerce apps need to remember what users have in their cart, even if they accidentally close the browser.

const shoppingCartStore = createStore('shopping-cart', {
  state: () => ({
    items: [],
    total: 0
  }),
  getters: {
    itemCount: (state) => state.items.length,
    isEmpty: (state) => state.items.length === 0
  },
  actions: {
    addItem(product) {
      const existingItem = this.items.find(item => item.id === product.id);
      if (existingItem) {
        existingItem.quantity += 1;
      } else {
        this.items.push({ ...product, quantity: 1 });
      }
      this.updateTotal();
    },
    removeItem(productId) {
      this.items = this.items.filter(item => item.id !== productId);
      this.updateTotal();
    },
    updateQuantity(productId, quantity) {
      const item = this.items.find(item => item.id === productId);
      if (item) {
        item.quantity = Math.max(0, quantity);
        if (item.quantity === 0) {
          this.removeItem(productId);
        } else {
          this.updateTotal();
        }
      }
    },
    updateTotal() {
      this.total = this.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
    },
    clearCart() {
      this.items = [];
      this.total = 0;
    }
  },
  persist: {
    adapter: new LocalStorageAdapter('shopping-cart'),
    debounceMs: 500,
    include: ['items', 'total']
  }
});

Try it yourself: Add items to your cart and refresh the page!

3. Multi-Step Form Persistence

Complex forms with multiple steps can be frustrating if users lose their progress.

const formStore = createStore('contact-form', {
  state: () => ({
    name: '',
    email: '',
    message: '',
    step: 1
  }),
  actions: {
    updateField(field, value) {
      this[field] = value;
    },
    nextStep() {
      if (this.step < 3) this.step++;
    },
    prevStep() {
      if (this.step > 1) this.step--;
    },
    resetForm() {
      this.name = '';
      this.email = '';
      this.message = '';
      this.step = 1;
    }
  },
  persist: {
    adapter: new LocalStorageAdapter('contact-form'),
    debounceMs: 100,
    transform: {
      out: (data) => {
        // Don't save empty fields
        const cleanData = {};
        Object.entries(data).forEach(([key, value]) => {
          if (value !== '' && value !== null && value !== undefined) {
            cleanData[key] = value;
          }
        });
        return cleanData;
      }
    }
  }
});

Try it yourself: Fill out the form steps and refresh the page!

4. Application State Persistence

Complex applications need to remember user preferences, filters, and view states.

const appStateStore = createStore('app-state', {
  state: () => ({
    currentView: 'dashboard',
    filters: {
      category: 'all',
      status: 'active',
      dateRange: 'week'
    },
    pagination: {
      page: 1,
      pageSize: 10
    },
    sidebarCollapsed: false
  }),
  actions: {
    setView(view) {
      this.currentView = view;
    },
    updateFilters(newFilters) {
      this.filters = { ...this.filters, ...newFilters };
      this.pagination.page = 1; // Reset to first page when filters change
    },
    setPage(page) {
      this.pagination.page = page;
    },
    toggleSidebar() {
      this.sidebarCollapsed = !this.sidebarCollapsed;
    }
  },
  persist: {
    adapter: new LocalStorageAdapter('app-state'),
    debounceMs: 200,
    exclude: ['pagination'] // Don't persist pagination for better UX
  }
});

Try it yourself: Change the view, filters, or sidebar state and refresh!

5. Cross-Tab Synchronization

Modern apps need to stay in sync across multiple browser tabs.

const crossTabStore = createStore('cross-tab-demo', {
  state: () => ({
    lastUpdated: new Date().toLocaleTimeString(),
    tabCount: 1
  }),
  actions: {
    updateTimestamp() {
      this.lastUpdated = new Date().toLocaleTimeString();
      this.tabCount++;
    }
  },
  persist: {
    adapter: new LocalStorageAdapter('cross-tab-demo'),
    debounceMs: 100
  }
});

Try it yourself: Open this page in multiple tabs and watch them sync!

Interactive Demos

Now let's see these concepts in action! Below are real, working examples of QuantaJS persistence:

Interactive QuantaJS Persistence Demos

These demos showcase real QuantaJS persistence features. Try them out!

Key Benefits of QuantaJS Persistence

🚀 Performance Optimized

  • Debounced Saves: Prevents excessive storage operations
  • Selective Persistence: Only save what you need
  • Efficient Updates: Minimal re-renders and storage writes

🛡️ Developer Friendly

  • Simple API: Just add persist to your store configuration
  • Type Safe: Full TypeScript support
  • Flexible: Multiple storage adapters and configuration options

🔄 Production Ready

  • Error Handling: Built-in error recovery and validation
  • Migration Support: Handle schema changes gracefully
  • Cross-Tab Sync: Automatic synchronization across browser tabs

Best Practices

1. Choose the Right Storage Adapter

  • LocalStorage: Good for small amounts of data, simple apps
  • SessionStorage: Perfect for temporary session data
  • IndexedDB: Best for large datasets and complex applications

2. Optimize with Debouncing

persist: {
  adapter: new LocalStorageAdapter('my-store'),
  debounceMs: 300 // Save after 300ms of inactivity
}

3. Use Selective Persistence

persist: {
  include: ['important', 'user', 'settings'], // Only persist these fields
  exclude: ['temporary', 'cache', 'pagination'] // Don't persist these
}

4. Transform Data When Needed

persist: {
  transform: {
    out: (data) => cleanData(data), // Clean before saving
    in: (data) => validateData(data) // Validate after loading
  }
}

5. Handle Errors Gracefully

persist: {
  onError: (error, operation) => {
    console.error(`Persistence ${operation} failed:`, error);
    // Fallback to default values or show user notification
  }
}

Real-World Use Cases

E-commerce Applications

  • Shopping cart persistence
  • User preferences and filters
  • Recently viewed products
  • Wishlist management

Productivity Tools

  • Form progress and drafts
  • User settings and preferences
  • Workspace layouts and configurations
  • Recent documents and projects

Gaming Applications

  • Game progress and achievements
  • User preferences and controls
  • High scores and statistics
  • Custom configurations

Social Media Platforms

  • User preferences and privacy settings
  • Feed filters and sorting options
  • Draft posts and comments
  • Notification preferences

Getting Started

Ready to add persistence to your QuantaJS stores? It's as simple as adding a persist configuration:

import { createStore, LocalStorageAdapter } from '@quantajs/core';

const myStore = createStore('my-store', {
  state: () => ({
    // Your state here
  }),
  actions: {
    // Your actions here
  },
  persist: {
    adapter: new LocalStorageAdapter('my-store'),
    debounceMs: 300
  }
});

Conclusion

Persistence is a game-changer for user experience. With QuantaJS, implementing robust persistence is straightforward and performant. The interactive demos above show real-world scenarios where persistence makes a significant difference.

Try out the demos, experiment with different configurations, and see how QuantaJS can transform your application's user experience. Remember, the best persistence strategy is one that's invisible to users but makes their experience seamless and delightful.

Happy coding! 🚀