Scrivere codice Better React con la separazione del principio di comando e query
Uno dei principi che utilizzo costantemente nel mio codice è una forma speciale o un uso concreto del principio di responsabilità unica al suo interno. Questo principio è il principio di separazione tra comando e interrogazione .
Il principio di separazione dei comandi e delle query è un principio di progettazione del software che suggerisce che i metodi o le funzioni dovrebbero essere comandi che modificano lo stato del sistema o query che restituiscono informazioni sullo stato del sistema, ma non entrambi.
I comandi (o modificatori) sono metodi che eseguono un'azione o modificano lo stato di un oggetto senza restituire un valore. Le query, d'altra parte, sono metodi che modificano lo stato di un oggetto. La separazione di comandi e query può aiutare a ridurre l'accoppiamento tra i componenti, semplificando il test, la manutenzione e la modifica del codice. Rende anche più facile ragionare sul comportamento del codice e può migliorare la progettazione complessiva di un sistema.
Il codice sottostante è considerato errato perché addIteme removeItemsta facendo più di una cosa: modificare i dati, aggiornare il prezzo totale e restituire il valore aggiornato.
class ShoppingCart {
constructor() {
this.items = [];
this.totalPrice = 0;
}
addItem(item) {
this.items.push(item);
this.updateTotalPrice();
return this.totalPrice;
}
removeItem(item) {
const index = this.items.indexOf(item);
if (index > -1) {
this.items.splice(index, 1);
this.updateTotalPrice();
}
return this.totalPrice;
}
updateTotalPrice() {
for (let i = 0; i < items.length; i++) {
this.totalPrice += items[i].price;
}
}
}
class ShoppingCart {
constructor() {
this.items = [];
this.totalPrice = 0;
}
addItem(item) {
this.items.push(item);
}
removeItem(item) {
const index = this.items.findIndex((item) => item.id === id);
if (index > -1) {
this.items.splice(index, 1);
}
}
get totalPrice () {
this.items.reduce((total, item) => total + item.price, 0)
}
}
In un'applicazione React, possiamo separare modificatori e query utilizzando una libreria di gestione dello stato come Redux o React Context API. Ciò consente di separare la logica per la modifica dello stato dell'applicazione dalla logica per il rendering dell'interfaccia utente.
Per saperne di più su Context e altri hook, puoi scaricare qui un cheat sheet contenente gli hook React più comuni con esempi e illustrazioni.
Questo principio di separazione delle responsabilità della query di comando può essere applicato a diversi livelli. A livello di architettura, potresti aver sentito parlare di CQRS in quel contesto. Essenzialmente, sono lo stesso principio applicato a diversi livelli di astrazione.
Esempio: carrello della spesa
Un'applicazione per il carrello della spesa potrebbe avere una ShoppingCartclasse che gestisce gli articoli del carrello e calcola il prezzo totale. I metodi addIteme removeItemnella ShoppingCartclasse sono comandi che modificano gli articoli del carrello, mentre il getTotalPricemetodo è una query che restituisce il prezzo totale degli articoli nel carrello.
Prima di applicare il principio di separazione del comando e della query, i metodi addIteme removeItempotrebbero anche aggiornare direttamente la proprietà del prezzo totale. Tuttavia, questo può rendere il codice più difficile da comprendere e mantenere.
Ecco un esempio di un componente React che gestisce un carrello della spesa:
import { useState, useMemo } from 'react';
function ShoppingCart() {
const [cart, setCart] = useState([]);
// Command: Add item to cart
function addItemToCart(item) {
setCart([...cart, item]);
}
// Command: Remove item from cart
function removeItemFromCart(id) {
setCart(cart.filter((item) => item.id !== id));
}
// Query: Calculate total price of items in cart
const totalPrice = useMemo(() => {
return cart.reduce((total, item) => total + item.price, 0);
}, [cart]);
return (
<div>
<h2>Shopping Cart</h2>
<ul>
{cart.map((item) => (
<li key={item.id}>
{item.name} - {item.price}
<button onClick={() => removeItemFromCart(item.id)}>Remove</button>
</li>
))}
</ul>
<p>Total Price: {totalPrice}</p>
</div>
);
}
Vantaggi della separazione comando-query
La separazione di comandi e query nel codice può fornire i seguenti vantaggi:
- Chiarezza: separando comandi e query, il codice diventa più facile da leggere e comprendere, poiché è più facile determinare cosa fa ogni metodo e cosa restituisce.
- Modularità: la separazione di comandi e query può rendere il codice più modulare e riutilizzabile, poiché i comandi e le query possono essere utilizzati in modo indipendente.
- Testabilità: la separazione di comandi e query può semplificare il test del codice, poiché l'isolamento e il test dei singoli metodi è più semplice.
- Complessità ridotta: la separazione di comandi e query può aiutare a ridurre la complessità del codice, in quanto incoraggia a suddividere operazioni complesse in parti più piccole e più gestibili.
D'altra parte, il principio introduce un'ulteriore astrazione extra nel codice che può rendere un po' più difficile il debug. L'utilizzo di un meccanismo pub-sub o listener di eventi per separare comandi e query può rendere più difficile eseguire il debug e ragionare sul comportamento del codice, specialmente quando il sito chiamante è lontano dai dati che modifica.
L'utilizzo di un'architettura ben definita e di uno stile di codifica coerente è essenziale per mantenere il codice organizzato e gestibile. È anche importante utilizzare nomi chiari e descrittivi per funzioni e variabili per rendere più comprensibile il loro scopo e comportamento.
Un altro approccio per separare comandi e query in un'applicazione React consiste nell'utilizzare una libreria di gestione dello stato come Redux o MobX. Queste librerie forniscono un archivio centralizzato per lo stato dell'applicazione e offrono un modo chiaro e strutturato per modificare e accedere allo stato da diverse parti dell'applicazione.
In Redux, ad esempio, possiamo definire le azioni come comandi che descrivono una modifica allo stato e i riduttori come query che gestiscono queste azioni e restituiscono un nuovo stato:
// Define actions
const addToCart = (item) => ({
type: 'ADD_TO_CART',
payload: item,
});
const removeItemFromCart = (id) => ({
type: 'REMOVE_FROM_CART',
payload: id,
});
// Define reducer
const cartReducer = (state = [], action) => {
switch (action.type) {
case 'ADD_TO_CART':
return [...state, action.payload];
case 'REMOVE_FROM_CART':
return state.filter((item) => item.id !== action.payload);
default:
return state;
}
};
Conclusione
Il principio di separazione tra comando e query è un principio importante da considerare durante la progettazione del software. La separazione di comandi e query rende il tuo codice più modulare, testabile e più facile da capire. Aderendo a questo principio, è possibile scrivere codice più facile da mantenere e meno soggetto a errori e bug.
In sintesi, separando il codice che modifica lo stato dal codice che restituisce informazioni sullo stato, è possibile creare un codice più modulare e verificabile, più facile da comprendere e gestire. Con una netta separazione tra comandi e query, è possibile ottenere un'architettura software più gestibile e scalabile.
Se ti piace la lettura, per favore Iscriviti alla mia mailing list . Condivido settimanalmente tecniche di Clean Code e Refactoring tramite blog , libri e video .

![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































