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 notationuseDb : base de données IndexedDB via DexieDocumentation IndexedDB Documentation Dexie Documentation Redux Toolkit
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.).
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é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 |
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' }
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é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 |
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]');
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 (/* ... */);
};
useDb ajoute automatiquement :
createdAt : timestamp de créationupdatedAt : timestamp de dernière modificationlogs : journal de toutes les opérations (create, update, delete)
// 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();
Si vous préférez utiliser Redux directement, SmartCommon fournit ReduxProvider.
// 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;
// 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";
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 (/* ... */);
};
| 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>