Skip to content

context preference

Paulo Gomes da Cruz Junior edited this page Nov 19, 2025 · 1 revision

⚙️ Preference Context

Overview

The PreferenceContext provides a centralized way to manage and persist user preferences across the application. It wraps the app with a PreferenceProvider, exposing both the current preferences and a method to update them. Preferences are stored in localStorage, ensuring they persist across sessions and page reloads.

The PreferenceProvider now leverages TanStack React Query for managing preference state, loading, and mutation. This enables more robust data fetching, caching, and synchronization of preferences, especially in complex or asynchronous scenarios.

This context is ideal for managing UI-related settings such as theme selection, language, or layout density. It’s designed to be extensible, allowing additional preferences to be added without disrupting the existing structure.

🧩 Context API

PreferenceContextType

type PreferenceContextType = {
  userPreference: UserPreference;
  updatePreferences: (preference: Partial<UserPreference>) => void;
};

UserPreference

type UserPreference = {
  theme: 'white' | 'g10' | 'g90' | 'g100';
  [key: string]: unknown;
};

Default Theme

const initialValue: UserPreference = {
  theme: 'g10',
};

🧪 Usage Example

import { usePreference } from '@/context/preference/usePreference';

const ThemeSelector = () => {
  const { userPreference, updatePreferences } = usePreference();

  const handleChange = (newTheme: string) => {
    updatePreferences({ theme: newTheme });
  };

  return (
    <select value={userPreference.theme} onChange={(e) => handleChange(e.target.value)}>
      <option value="white">White</option>
      <option value="g10">Gray 10</option>
      <option value="g90">Gray 90</option>
      <option value="g100">Gray 100</option>
    </select>
  );
};

🧠 Implementation Details

  • React Query Integration: The PreferenceProvider uses useQuery to load preferences and useMutation to update them. This ensures preference state is always in sync and can be refetched or updated reactively.
  • Persistence: Preferences are loaded from and saved to localStorage using loadUserPreference and saveUserPreference, but now through React Query's data management.
  • Extensibility: The UserPreference type supports additional keys, making it easy to expand.
  • Safety: The usePreference hook ensures it’s only used within a valid provider context, throwing an error otherwise.

🛠️ Utilities & React Query API

  • useQuery({ queryKey: ['userPreference'], queryFn: loadUserPreference }): Loads preferences from localStorage and keeps them in sync with the provider state.
  • useMutation({ mutationFn: saveUserPreference }): Updates and persists preferences, triggering state updates and cache invalidation as needed.
  • loadUserPreference(): Reads preferences from localStorage, falling back to defaults if none exist.
  • saveUserPreference(preference): Merges and stores updated preferences.

Example: Provider Implementation (with React Query)

import { useQuery, useMutation } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import { PreferenceContext } from './PreferenceContext';
import { loadUserPreference, saveUserPreference } from './utils';

export const PreferenceProvider = ({ children }) => {
  const [userPreference, setUserPreference] = useState(loadUserPreference());

  const queryUserPreference = useQuery({
    queryKey: ['userPreference'],
    queryFn: loadUserPreference,
    refetchOnMount: true,
  });

  const mutateUserPreference = useMutation({
    mutationFn: async (updatedPreferences) => {
      return Promise.resolve(saveUserPreference(updatedPreferences));
    },
  });

  const updatePreferences = (preference) => {
    const updatedPreferences = {
      ...userPreference,
      ...preference,
    };
    setUserPreference(updatedPreferences);
    mutateUserPreference.mutate(updatedPreferences);
  };

  useEffect(() => {
    if (queryUserPreference.isSuccess) {
      setUserPreference(queryUserPreference.data);
    }
  }, [queryUserPreference]);

  const contextValue = {
    userPreference,
    updatePreferences,
  };

  return <PreferenceContext.Provider value={contextValue}>{children}</PreferenceContext.Provider>;
};

Clone this wiki locally