Back
Tech 3 min read - 3 Nov 22 - Mayeul Le Monies de Sagazan

Proxies and reactivity in JavaScript

Have you ever wondered how JavaScript libraries work that update the page when you modify a variable directly without using a "setter"? They probably use a JavaScript Proxy!
In this article, we will first explain what a JavaScript proxy is, then we will create an example of a reactive page using a proxy.

What's a proxy in JavaScript?

ECMAScript 2015 (ES6) introduced a new concept in JavaScript: proxies.
These proxies serve to wrap a JavaScript object to intercept the fundamental operations that could be applied to the object. These operations are, for example, accessing and modifying an object's properties.
Is it a bit vague? Everything will become clearer with examples:
const proxy = new Proxy(target, handlers);
Where target is the object to wrap and handlers are the fundamental operations we talked about earlier.
Now, let's try the operation get, the function takes 2 things as parameters:
  • the wrapped object (target)
  • the name of the property we are trying to access (property)
const proxy = new Proxy({age: 21}, {
  get(target, property) {
    console.log(`Lecture de target.${property}`);
    return target[property];
  }
});
console.log(proxy.age)
Will display:
Lecture de target.age
21
Next, the operation set, it takes 3 things as parameters:
  • the wrapped object (target)
  • the name of the property we are trying to access (property)
  • the new value (value)
const proxy = new Proxy({age: 21}, {
  set(target, property, value) {
    target[property] = value + 1;
  }
});
proxy.age = 41;
console.log(proxy.age);
Will display:
42
There are other operations than get and set but I'll let you discover them yourself if you wish.

Creating a reactive page using a proxy

We are going to create a page that displays:
  • the user's current age
  • the user's age in 10, 20, and 30 years
We are going to make sure that this page updates as soon as the "age" variable is changed.
First, we create a basic HTML page and in the body, we put:
<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>
Next, we wrap the state of our page in a proxy:
window.ReactiveSystem = {
  state: new Proxy({ age: 0 }, {})
}
Then, we add the system that will allow a function to be launched every time a property of the object is modified.
For this, I chose to have a Map that links the property name with the function that should be called when the property changes:
window.ReactiveSystem.onChangeHandler = new Map();
We add a function to easily associate a property with a function:
window.ReactiveSystem.addOnChangeHandler = (property, handler) => {
  window.ReactiveSystem.onChangeHandler.set(property, handler);
}
We add a function to easily launch the "onChange" function associated with a property:
window.ReactiveSystem.runOnChangeHandler = (property) => {
  const handler = window.ReactiveSystem.onChangeHandler.get(property);
  handler?.(window.ReactiveSystem.state[property]);
}
Next, we add a function to add a new reactive property to our page:
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);
}
Finally, we change the set of our proxy so that it calls our function runOnChangeHandler
window.ReactiveSystem.state = newProxy({}, {
  set(target,propertyName,value) {
    target[propertyName] = value;
    window.ReactiveSystem.runOnChangeHandler(propertyName);
  },
});
Now that our system is finished, all that remains is to use it; for this, we create a function that will update the things related to the age the user will enter:
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();
}
Finally, we need to use our function addState :
window.ReactiveSystem.addState('age', 21, renderAgeThings);
If we want the age to change when the user modifies their age with the text input, we will need to add:
document.getElementById('ageInput').addEventListener('input', (e) => {
  window.ReactiveSystem.state.age = e.target.value
})
It's done! Now, if we open the JavaScript console in the development tools and modify the property window.ReactiveSystem.age, the page content is updated!
Here are the links to test or view the full code.

Do you want support to launch your digital project?

Submit your project now