SmarMaker - Documentation
Docs» 03_front:stockage_de_donnees

# Stockage de données

SmartCommon propose plusieurs solutions pour le stockage de données côté client :

  • useGlobalStates : état global avec persistance automatique (localStorage/sessionStorage)
  • useStates : état local réactif avec path notation
  • useDb : base de données IndexedDB via Dexie
  • useCachedQuery : cache de données avec stratégies (NetworkFirst, CacheFirst, SWR)

Pour la synchronisation offline complète, voir Synchronisation offline (useSyncClient).

Documentation [IndexedDB](https://developer.mozilla.org/fr/docs/Web/API/IndexedDB_API) Documentation [Dexie](https://dexie.org/) Documentation [Redux Toolkit](https://redux-toolkit.js.org/)

## useGlobalStates (recommandé)

Le hook useGlobalStates fournit un état global avec persistance automatique. C'est la méthode recommandée pour les données utilisateur (session, préférences, etc.).

### Utilisation basique

``` import { useGlobalStates } from '@cap-rel/smartcommon';

export const MyComponent = () ⇒ {

const gst = useGlobalStates();
// Lire une valeur
const user = gst.get('user');
// Écrire dans localStorage (persistant)
const login = (userData) => {
  gst.local.set('user', userData);
};
// Écrire dans sessionStorage (session uniquement)
const setTempData = (data) => {
  gst.session.set('tempData', data);
};
// Supprimer une valeur
const logout = () => {
  gst.unset('user');
};
return (
  <div>
    {user ? `Bonjour ${user.name}` : 'Non connecté'}
  </div>
);

}; ```

### Méthodes disponibles

Méthode Description
gst.get(path) Récupère une valeur par son chemin
gst.local.set(path, value) Stocke dans localStorage (persistant)
gst.session.set(path, value) Stocke dans sessionStorage (session)
gst.unset(path) Supprime une valeur
gst.values Objet contenant toutes les valeurs

### Path notation

Vous pouvez accéder aux données imbriquées avec la notation par points :

``` // Définir des données imbriquées gst.local.set('user.preferences.theme', 'dark'); gst.local.set('user.preferences.language', 'fr');

// Lire des données imbriquées const theme = gst.get('user.preferences.theme'); // 'dark' const prefs = gst.get('user.preferences'); // { theme: 'dark', language: 'fr' } ```

## useStates (état local)

Le hook useStates fournit un état local réactif avec la même API que useGlobalStates.

``` import { useStates } from '@cap-rel/smartcommon';

export const MyForm = () ⇒ {

const st = useStates({
  initialStates: {
    name: '',
    email: '',
    errors: {}
  },
  debug: true // affiche les changements dans la console
});
const handleChange = (field, value) => {
  st.set(field, value);
};
const validate = () => {
  if (!st.get('name')) {
    st.set('errors.name', 'Le nom est requis');
  }
};
return (
  <form>
    <Input
      value={st.get('name')}
      onChange={(e) => handleChange('name', e.target.value)}
      error={st.get('errors.name')}
    />
  </form>
);

}; ```

### Méthodes disponibles

Méthode Description
st.get(path) Récupère une valeur
st.set(path, value) Définit une valeur
st.unset(path) Supprime une valeur
st.values Objet contenant toutes les valeurs
st.states Alias de values

### Manipulation de tableaux

``` const st = useStates({ initialStates: { items: [] } });

// Ajouter un élément (push) st.set('items[]', { id: 1, name: 'Item 1' });

// Modifier un élément par index st.set('items[0].name', 'Item modifié');

// Supprimer un élément par index st.unset('items[0]'); ```

## useCachedQuery (cache avec stratégies)

Le hook useCachedQuery permet de mettre en cache les données API dans IndexedDB avec des stratégies configurables.

``` import { useCachedQuery } from '@cap-rel/smartcommon';

const ItemsList = () ⇒ {

const db = useMemo(() => new Dexie('myApp'), []);
const {
  data,          // données (depuis cache ou réseau)
  isLoading,     // chargement en cours
  isFromCache,   // true si les données viennent du cache
  isStale,       // true si les données sont périmées
  error,         // erreur éventuelle
  lastFetch,     // timestamp du dernier fetch
  refetch,       // forcer un nouveau fetch
  invalidate,    // invalider le cache
} = useCachedQuery({
  db,
  store: 'cache',         // nom du store IndexedDB (schéma: 'key')
  key: 'items-list',      // clé de cache unique
  fetchFn: () => api.get('items'),  // fonction de récupération
  strategy: 'networkFirst',         // stratégie de cache
  ttl: 3600000,           // durée de vie du cache (1h par défaut)
  staleTime: 60000,       // durée avant que le cache soit "stale" (1min par défaut)
  enabled: true,          // activer/désactiver le fetch
});
if (isLoading) return <Spinner />;
return (
  <List>
    {data?.map(item => (
      <ListItem key={item.id}>{item.label}</ListItem>
    ))}
  </List>
);

}; ```

### Stratégies disponibles

Stratégie Constante Comportement
networkFirst NETWORK_FIRST Réseau d'abord, cache en fallback (défaut)
cacheFirst CACHE_FIRST Cache d'abord, réseau si absent ou expiré
swr STALE_WHILE_REVALIDATE Retourne le cache immédiatement, revalide en arrière-plan

``` import { CACHE_STRATEGIES } from '@cap-rel/smartcommon';

// Utilisation avec constante useCachedQuery({

// ...
strategy: CACHE_STRATEGIES.STALE_WHILE_REVALIDATE,

}); ```

## useDb (IndexedDB)

Pour stocker de grandes quantités de données ou des données structurées complexes, utilisez useDb basé sur Dexie.

``` import { useDb } from '@cap-rel/smartcommon';

// Définir la base de données const db = useDb({

name: 'myApp',
version: 1,
stores: {
  items: 'id++, name, category, createdAt',
  categories: 'id++, name'
},
debug: true

});

export const ItemsManager = () ⇒ {

const [items, setItems] = useState([]);
// Charger les items
useEffect(() => {
  db.items.toArray().then(setItems);
}, []);
// Ajouter un item
const addItem = async (item) => {
  const id = await db.items.add(item);
  console.log('Item added with id:', id);
};
// Modifier un item
const updateItem = async (id, changes) => {
  await db.items.update(id, changes);
};
// Supprimer un item
const deleteItem = async (id) => {
  await db.items.delete(id);
};
// Requête avec filtre
const getByCategory = async (category) => {
  return db.items.where('category').equals(category).toArray();
};
return (/* ... */);

}; ```

### Fonctionnalités automatiques

useDb ajoute automatiquement :

  • createdAt : timestamp de création
  • updatedAt : timestamp de dernière modification
  • Table logs : journal de toutes les opérations (create, update, delete)

### Requêtes Dexie

``` // Tous les items const all = await db.items.toArray();

// Par clé primaire const item = await db.items.get(1);

// Filtrer const filtered = await db.items

.where('category')
.equals('electronics')
.toArray();

// Trier const sorted = await db.items

.orderBy('createdAt')
.reverse()
.toArray();

// Limiter const first10 = await db.items.limit(10).toArray();

// Compter const count = await db.items.count(); ```

<note tip>Pour un cache API avec stratégies automatiques, préférez useCachedQuery. Pour la synchronisation offline complète avec gestion de conflits, utilisez useSyncClient.</note>

## Redux (méthode classique)

Si vous préférez utiliser Redux directement, SmartCommon fournit ReduxProvider.

### Créer un slice

``` // src/redux/reducers/sessionSlice.js

import { createSlice } from “@reduxjs/toolkit”;

const initialState = {

data: JSON.parse(sessionStorage.getItem("session")) ?? null

};

const sessionSlice = createSlice({

name: "session",
initialState,
reducers: {
  setSession(state, action) {
    state.data = action.payload;
    sessionStorage.setItem("session", JSON.stringify(action.payload));
  },
  unsetSession(state) {
    state.data = null;
    sessionStorage.removeItem("session");
  }
},

});

export default sessionSlice.reducer; export const { setSession, unsetSession } = sessionSlice.actions; ```

### Configurer le store

``` // src/redux/index.js

import sessionReducer from “./reducers/sessionSlice”; import { combineReducers } from “redux”; import { configureStore } from “@reduxjs/toolkit”;

const rootReducer = combineReducers({

session: sessionReducer

});

export const reduxStore = configureStore({ reducer: rootReducer }); export * from “./reducers/sessionSlice”; ```

### Utiliser dans les composants

``` import { useSelector, useDispatch } from “react-redux”; import { setSession, unsetSession } from “../../../redux”;

export const MyComponent = () ⇒ {

const session = useSelector(state => state.session.data);
const dispatch = useDispatch();
const login = (data) => dispatch(setSession(data));
const logout = () => dispatch(unsetSession());
return (/* ... */);

}; ```

## Comparaison des méthodes

Méthode Cas d'usage Persistance
useGlobalStates Session utilisateur, préférences localStorage / sessionStorage
useStates État de formulaire, UI locale Mémoire (non persistant)
useDb Données structurées, stockage local IndexedDB
useCachedQuery Cache API avec stratégies IndexedDB
useSyncClient Synchronisation offline complète IndexedDB
Redux Applications complexes, middleware Configurable

<note tip>Pour la plupart des cas, useGlobalStates et useStates suffisent. Pour un stockage IndexedDB simple, utilisez useDb. Pour le cache de données API, utilisez useCachedQuery. Pour le mode offline complet avec synchronisation, utilisez useSyncClient.</note>

## Voir aussi

  • Hooks - Documentation complète des hooks
  • Requêtes API - Combiner avec les appels API
Previous Next

Made with ❤ by CAP-REL · SmartMaker · GNU AGPL v3+
Code source · Faire un don
SmarMaker - Documentation
Traductions de cette page:
  • Français
  • Deutsch
  • English
  • Español
  • Italiano
  • Nederlands

Table of Contents

  • SmartAuth
  • SmartMaker - Back (PHP)
    • Mapping Dolibarr - React
  • SmartMaker - Front (React)
    • Animations de pages
    • Architecture
    • Astuces
    • Calendar
    • Composants avancés (high-level)
    • Composants et pages
    • Configuration du Provider
    • Debug et Logs
    • Hooks SmartCommon
    • PWA (Progressive Web App)
    • Requêtes API
    • Routage
    • SmartCommon
    • Stockage de données
    • Synchronisation offline
    • Thèmes
    • Traductions
  • HowTo - Pas à pas - Votre première application
    • Développement PHP (back)
    • Développement React (front)
    • Première étape : Module Builder Dolibarr
    • SmartAuth
    • SmartBoot : Un squelette prêt à l'emploi
  • Formation SmartMaker
    • Module 1 : Fondamentaux JavaScript ES6+
      • Chapitre 1 : Variables et Scope
      • Chapitre 2 : Fonctions
      • Chapitre 3 : Programmation Asynchrone
      • Chapitre 4 : Modules ES6
    • Module 2 : Introduction à React
      • Chapitre 1 : Philosophie React
      • Chapitre 2 : JSX
      • Chapitre 3 : Composants
    • Module 3 : Hooks React Fondamentaux
      • Chapitre 1 : useState
      • Chapitre 2 : useEffect
      • Chapitre 3 : useRef
      • Chapitre 4 : useContext
    • Module 4 : React Avancé
      • Chapitre 1 : useCallback et useMemo
      • Chapitre 2 : Custom Hooks
      • Chapitre 3 : Redux et Redux Toolkit
    • Module 5 : Architecture SmartMaker
      • Chapitre 1 : Structure du projet
      • Chapitre 2 : Configuration
      • Chapitre 3 : Flux de données
    • Module 6 : SmartCommon - Composants
      • Chapitre 1 : Mise en page
      • Chapitre 2 : Navigation
      • Chapitre 3 : Formulaires
      • Chapitre 4 : Affichage
    • Module 7 : SmartCommon - Hooks
      • Chapitre 1 : useApi
      • Chapitre 2 : Gestion d'état
      • Chapitre 3 : Hooks utilitaires
      • Chapitre 4 : Synchronisation Offline
    • Module 8 : Backend API (PHP)
      • Chapitre 1 : Routage
      • Chapitre 2 : Controllers
      • Chapitre 3 : Mappers
      • Extrafields et formulaires dynamiques
    • Module 9 : Intégration complète
      • Chapitre 1 : Backend
      • Chapitre 2 : Frontend
      • Chapitre 3 : Déploiement
    • Module 10 : Fonctionnalités avancées
      • Chapitre 1 : Mode offline
      • Chapitre 2 : Internationalisation (i18n)
      • Chapitre 3 : Autres fonctionnalités
    • Module 11 : Bonnes pratiques
  • Démonstration
  • Start
  • Composants et pages
  • Afficher le texte source
  • Anciennes révisions
  • Liens de retour
  • Haut de page