# 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 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 (
{user ? `Bonjour ${user.name}` : 'Non connecté'}
); }; ``` ### 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 (
handleChange('name', e.target.value)} error={st.get('errors.name')} />
); }; ``` ### 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 : * ''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(); ``` ## 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 | 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). ## Voir aussi * [[hooks|Hooks]] - Documentation complète des hooks * [[requetes_api|Requêtes API]] - Combiner avec les appels API