Skip to content

State Management for Personalization Flow in Statista 4.0

Date: 2025-10-17

Status: accepted

Context

We need to move a Personalization flow from Vue.js implementation in monolith to Remix and Statista 4.0. Currently Personalization flow consists of 4 steps where we enable users to select multiple items at each step. After every step submission we send a Mercury event to track selected data. The monolith implementation is currently client-only. We want to keep this functionality as it is, but adjust it for the new Statista 4.0 stack

The solution must:

  • Maintain selections across all 4 steps
  • Work with browser navigation (back/forward)
  • Respect user privacy (avoid unnecessary cookies)
  • Out of scope: persist selection after page refreshes
  • Out of scope: persist selection outside of personalization route

Evaluated Approaches

1. Database Storage (Future Solution)

Description: Save form data to database

Pros:

  • ✅ Most reliable and persistent
  • ✅ Works across devices
  • ✅ Can resume days/weeks later

Cons:

  • ❌ More complex implementation

Verdict: 🔮 Future Iteration - In future iterations we would like to allow users to retain their settings across sessions. However, for now to keep things simple we still rely on Personalization flow being client-side only and using Mercury as an event-bus. The following approaches are client-only solutions we evaluated for the current implementation.


2. URL Search Parameters

Description: Store all selections in URL query parameters

Pros:

  • ✅ Shareable links
  • ✅ Browser back/forward works natively
  • ✅ No storage needed
  • ✅ SEO-friendly and bookmarkable

Cons:

  • ❌ URLs become extremely long with multiple selections
  • ❌ Ugly user experience with messy URLs
  • ❌ Data visible in browser history and server logs

Verdict: ❌ Not suitable for multi-selection across 4 steps


3. Session Storage (Cookies)

Description: Store form state in server-side session via cookies

Pros:

  • ✅ Handles large amounts of data
  • ✅ Secure (server-side)
  • ✅ Persists across page refreshes
  • ✅ Clean URLs
  • ✅ Can set expiration time

Cons:

  • Requires setting cookies (privacy concern)
  • ❌ Needs cookie consent in GDPR regions
  • ❌ Additional server infrastructure
  • ❌ Doesn't work across devices
  • ❌ Session management complexity

Verdict: ❌ Rejected due to privacy requirements


4. Hidden Form Fields

Description: Pass all previous step data through hidden inputs

Pros:

  • ✅ Works without JavaScript
  • ✅ Progressive enhancement friendly
  • ✅ No external storage needed
  • ✅ Simple to implement

Cons:

  • ❌ Data duplicated at each step
  • ❌ Large form payloads
  • ❌ Complex to manage across 4 steps

Verdict: ❌ Too complex for 4-step flow


5. localStorage Only

Description: Store all state in browser's localStorage

Pros:

  • ✅ No cookies required
  • ✅ Persists across refreshes
  • ✅ Large storage capacity (5-10MB)
  • ✅ Privacy-friendly (client-side only)
  • ✅ Simple implementation

Cons:

  • ❌ Doesn't work server-side (SSR issues)
  • ❌ Lost if user clears browser data
  • ❌ Doesn't sync across devices
  • ❌ Race conditions with multiple tabs

Verdict: ⚠️ Good, but needs hydration handling


6. React Context (In-Memory Only)

Description: Use React Context for in-memory state management during active session

Pros:

  • No cookies required (privacy-friendly)
  • No browser storage required (maximum privacy)
  • ✅ Fast in-memory access during session
  • ✅ Clean URLs
  • ✅ Simple implementation
  • ✅ Easy to access from any component
  • ✅ SSR-compatible (no hydration issues)
  • ✅ Handles large selection sets
  • ✅ Automatically cleared on page close/refresh (no cleanup needed)

Cons:

  • ⚠️ Lost on page refresh (acceptable - encourages completion in one session)
  • ⚠️ Lost if user navigates away (expected behavior)

Verdict: ⚠️ ALTERNATIVE CONSIDERED - Good but unnecessary complexity


7. Parameterized Route State (Primary Approach) ⭐

Description: Store selected options as React state within a single route component that handles all steps via URL parameters

Pros:

  • Natural state persistence during navigation (component stays mounted)
  • Cross-step features possible (state available across all steps)
  • Simplest possible implementation (single route component)
  • ✅ No external dependencies or context providers needed
  • ✅ Fast in-memory access during entire flow
  • ✅ SSR-compatible (no hydration issues)
  • ✅ Privacy-friendly (state cleared on page refresh)
  • ✅ Clean URLs with semantic step parameters
  • ✅ Browser back/forward navigation works naturally

Cons:

  • ⚠️ State lost on page refresh (but persists during personalization flow navigation)
  • ⚠️ Lost if user navigates away from personalization flow (expected behavior)

How persistence works:

  • Single route component (personalization.$step/route.tsx) handles all steps
  • Navigation between steps (e.g., /account-purpose/industries) doesn't unmount the component
  • React state persists because the same component instance renders all steps
  • Only the step parameter changes, triggering re-renders with preserved state

Verdict:Primary Approach - Simple with cross-step capabilities


Decision

Primary Approach: Parameterized Route State (Route-Level State)
Alternative Considered: React Context (In-Memory Only)

Rationale:

For Parameterized Route State approach (selected):

  1. Maximum privacy - no state persistence beyond session
  2. Simplest possible implementation - single route component handles all steps
  3. Cross-step features enabled - state naturally available across all steps
  4. Minimal complexity - no context providers or state management overhead

Consequences

In the future, we plan to introduce a database as a permanent data storage solution, allowing users to retain their settings across sessions. For this initial iteration, however, we will use a client-only state approach to keep effort and complexity low and focus on migrating the existing functionality to the Statista 4.0 stack.