Ritorno
Tech 3 min di lettura - 3 nov. 22 - Mayeul Le Monies de Sagazan

I Proxy e la reattività in JavaScript

Ti sei mai chiesto come funzionavano le librerie JavaScript che aggiornano la pagina quando modifichi una variabile direttamente senza usare un "setter"? Probabilmente usano un Proxy JavaScript!
In questo articolo, spiegheremo prima che cos'è un proxy JavaScript, poi creeremo un esempio di pagina reattiva grazie a un proxy.

Che cos'è un proxy in JavaScript?

ECMAScript 2015 (ES6) ha introdotto un nuovo concetto in JavaScript: i proxy.
Questi proxy servono a wrappare un oggetto JavaScript per intercettare le operazioni fondamentali che si potrebbero applicare sull'oggetto. Queste operazioni sono, per esempio, l'accesso e la modifica delle proprietà di un oggetto.
È un po' confuso? Tutto si chiarirà con degli esempi:
const proxy = new Proxy(target, handlers);
Dove target è l'oggetto da wrappare e handlers sono le operazioni fondamentali di cui abbiamo parlato più sopra.
Ora, proviamo l'operazione get, la funzione prende in parametro 2 cose:
  • l'oggetto wrappato (target)
  • il nome della proprietà a cui si cerca di accedere (property)
const proxy = new Proxy({age: 21}, {
  get(target, property) {
    console.log(`Lecture de target.${property}`);
    return target[property];
  }
});
console.log(proxy.age)
Mostrerà:
Lecture de target.age
21
In seguito, l'operazione set, prende in parametro 3 cose:
  • l'oggetto wrappato (target)
  • il nome della proprietà a cui si cerca di accedere (property)
  • il nuovo valore (value)
const proxy = new Proxy({age: 21}, {
  set(target, property, value) {
    target[property] = value + 1;
  }
});
proxy.age = 41;
console.log(proxy.age);
Mostrerà:
42
Esistono altre operazioni oltre a get e set ma ti lascio scoprirle tu stesso se ne hai voglia.

Creazione di una pagina reattiva grazie a un proxy

Creeremo una pagina che mostra:
  • l'età attuale dell'utente
  • l'età dell'utente tra 10 anni, 20 anni e 30 anni
Faremo in modo che questa pagina si aggiorni non appena si cambia la variabile "age".
Innanzitutto, facciamo una pagina HTML di base e nel body, mettiamo:
<body>
  <p>Votre age :</p>
  <input id="ageInput" type="text">
  <h2 id="yourAge"></h2>
  <h2 id="plusTenYears"></h2>
  <h2 id="plusTwentyYears"></h2>
  <h2 id="plusThirtyYears"></h2>
</body>
In seguito, wrappiamo lo stato della nostra pagina in un proxy:
window.ReactiveSystem = {
  state: new Proxy({ age: 0 }, {})
}
Poi, aggiungiamo il sistema che permetterà di lanciare una funzione ogni volta che si modifica una proprietà dell'oggetto.
Per questo, ho scelto di avere una Map che lega il nome della proprietà con la funzione da chiamare quando la proprietà cambia:
window.ReactiveSystem.onChangeHandler = new Map();
Aggiungiamo una funzione per associare facilmente una proprietà a una funzione:
window.ReactiveSystem.addOnChangeHandler = (property, handler) => {
  window.ReactiveSystem.onChangeHandler.set(property, handler);
}
Aggiungiamo una funzione per lanciare facilmente la funzione "onChange" associata a una proprietà:
window.ReactiveSystem.runOnChangeHandler = (property) => {
  const handler = window.ReactiveSystem.onChangeHandler.get(property);
  handler?.(window.ReactiveSystem.state[property]);
}
In seguito, aggiungiamo una funzione per aggiungere una nuova proprietà reattiva sulla nostra pagina:
window.ReactiveSystem.addState = (property, state, onChangeHandler) => {
  window.ReactiveSystem.state[property] = state;
  window.ReactiveSystem.addOnChangeHandler(property, onChangeHandler);
  // on lance directement le onChange après l'ajout de la propriété pour que le premier rendu soit correct
  window.ReactiveSystem.runOnChangeHandler(name);
}
Infine, cambiamo il set del nostro proxy affinché chiami la nostra funzione runOnChangeHandler
window.ReactiveSystem.state = newProxy({}, {
  set(target,propertyName,value) {
    target[propertyName] = value;
    window.ReactiveSystem.runOnChangeHandler(propertyName);
  },
});
Ora che il nostro sistema è finito, non ci resta che usarlo; per farlo, creiamo una funzione che aggiornerà le cose legate all'età che l'utente inserirà:
const renderAgeThings = (value) => {
  const rawAge = +value;
  const age = isNaN(rawAge) ? 0 : rawAge;
  const agePlusTen = `Dans 10 ans vous aurez ${age+10} ans`;
  const agePlusTwenty = `Dans 20 ans vous aurez ${age+20} ans`;
  const agePlusThirty = `Dans 30 ans vous aurez ${age+30} ans`;

  document.getElementById('yourAge').innerHTML = `Vous avez ${age} ans`;
  document.getElementById('plusTenYears').innerHTML = agePlusTen;
  document.getElementById('plusTwentyYears').innerHTML = agePlusTwenty;
  document.getElementById('plusThirtyYears').innerHTML = agePlusThirty;

  document.getElementById('ageInput').value = age.toString();
}
Infine, dobbiamo usare la nostra funzione addState :
window.ReactiveSystem.addState('age', 21, renderAgeThings);
Se vogliamo che l'età cambi quando l'utente modifica la sua età con il campo di testo, dovremo aggiungere:
document.getElementById('ageInput').addEventListener('input', (e) => {
  window.ReactiveSystem.state.age = e.target.value
})
È finita! Ora, se apriamo la console JavaScript negli strumenti di sviluppo e modifichiamo la proprietà window.ReactiveSystem.age, il contenuto della pagina si aggiorna!

Desideri essere accompagnato per lanciare il tuo progetto digitale ?

Invia il tuo progetto ora