Table des matières

Stockage de données

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

Documentation IndexedDB Documentation Dexie Documentation Redux Toolkit

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]');

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 ajouté avec 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 :

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();

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 Grandes quantités de données, offline IndexedDB
Redux Applications complexes, middleware Configurable

<note tip>Pour la plupart des cas, useGlobalStates et useStates suffisent. Utilisez useDb uniquement pour des besoins spécifiques (mode offline, grandes quantités de données).</note>

Voir aussi