In questo articolo costruiremo un carrello e-commerce con React Redux e Redux Toolkit, seguendo le pratiche consigliate.
Perché usare Redux Toolkit con React Redux
- API moderne e concise (createSlice, configureStore) riducono il boilerplate.
- Performance e DX: integrazione con DevTools, middleware preconfigurati e tipizzazione facilitata.
- Compatibilità aggiornata: React Redux è allineato a React e a build ESM/CJS moderne.
Installazione
npm install @reduxjs/toolkit react-redux
Struttura minima
src/app/store.js— configurazione dello storesrc/features/cart/cartSlice.js— stato e reducer del carrellosrc/App.jsx— UI (lista prodotti + carrello)src/main.jsx— bootstrap React con<Provider>
Slice del carrello
// src/features/cart/cartSlice.js
import { createSlice, createSelector } from '@reduxjs/toolkit';
const initialState = {
// mappa id => { id, name, price, qty }
items: {}
};
const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
addedToCart(state, action) {
const p = action.payload; // {id, name, price}
const curr = state.items[p.id];
state.items[p.id] = curr
? { ...curr, qty: curr.qty + 1 }
: { ...p, qty: 1 };
},
removedFromCart(state, action) {
delete state.items[action.payload]; // payload = productId
},
changedQty(state, action) {
const { id, qty } = action.payload;
if (state.items[id]) {
state.items[id].qty = Math.max(1, qty);
}
},
clearedCart(state) {
state.items = {};
}
}
});
export const { addedToCart, removedFromCart, changedQty, clearedCart } = cartSlice.actions;
export default cartSlice.reducer;
// --- Selectors ---
const selectCartState = (root) => root.cart;
export const selectItemsArray = createSelector(
selectCartState,
(cart) => Object.values(cart.items)
);
export const selectCount = createSelector(selectItemsArray, (arr) =>
arr.reduce((sum, it) => sum + it.qty, 0)
);
export const selectTotal = createSelector(selectItemsArray, (arr) =>
arr.reduce((sum, it) => sum + it.qty * it.price, 0)
);
Store Redux
// src/app/store.js
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from '../features/cart/cartSlice';
export const store = configureStore({
reducer: {
cart: cartReducer
}
});
// Tip: in DevTools vedrai le azioni e lo stato senza configurazioni extra
Bootstrap
// src/main.jsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from './App';
createRoot(document.getElementById('root')).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
UI di esempio: lista prodotti + carrello
// src/App.jsx
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
addedToCart,
removedFromCart,
changedQty,
clearedCart,
selectItemsArray,
selectCount,
selectTotal
} from './features/cart/cartSlice';
const products = [
{ id: 'p1', name: 'T-shirt', price: 19.9 },
{ id: 'p2', name: 'Sneakers', price: 79.0 },
{ id: 'p3', name: 'Zaino', price: 49.5 }
];
export default function App() {
const dispatch = useDispatch();
const items = useSelector(selectItemsArray);
const count = useSelector(selectCount);
const total = useSelector(selectTotal);
return (
<>
<h1>E-commerce Demo</h1>
<h2>Prodotti</h2>
{products.map(p => (
<figure key={p.id}>
<figcaption>{p.name} — € {p.price.toFixed(2)}</figcaption>
<button onClick={() => dispatch(addedToCart(p))}>Aggiungi al carrello</button>
</figure>
))}
<h2>Carrello ({count})</h2>
{items.length === 0 ? (
<p>Il tuo carrello è vuoto.</p>
) : (
<ul>
{items.map(it => (
<li key={it.id}>
<strong>{it.name}</strong> — € {it.price.toFixed(2)}
×
<input
type="number"
min="1"
value={it.qty}
onChange={(e) =>
dispatch(changedQty({ id: it.id, qty: Number(e.target.value) }))
}
style={{ width: 56 }}
/>
<button onClick={() => dispatch(removedFromCart(it.id))}>Rimuovi</button>
</li>
))}
</ul>
)}
<p><strong>Totale:</strong> € {total.toFixed(2)}</p>
<button onClick={() => dispatch(clearedCart())}>Svuota carrello</button>
</>
);
}
Note importanti
- React 18 obbligatorio per React Redux 9 (niente supporto a React 16/17).
- Versioni attuali: React Redux 9.2.0 su npm; Redux Toolkit 2.9.0 su GitHub. Controlla sempre i changelog prima di aggiornare.
- Starter consigliati: template ufficiale Redux+TS per Vite o Next.js con Redux preconfigurato.
Estensioni utili
- Persistenza: salva lo stato del carrello su
localStoragecon un middleware custom. - RTK Query: gestisci il catalogo prodotti remoto (fetch, cache, polling) separando “server state” dal carrello.
Conclusione
Con React Redux e Redux Toolkit ottieni uno store semplice da configurare, reducer espressivi e selettori performanti. La base mostrata qui è pronta per crescere: aggiungi autenticazione, persistenza, pagamenti e integrazioni API mantenendo uno stato globale prevedibile e testabile.