# State

thorium-states / [Documentation](docs/modules.md)

Le projet **`States`** implémente une solution pour gérer l'état global d'une application JavaScript en utilisant la notion d'objets immuables. Cela signifie que lorsque vous voulez mettre à jour l'état de votre application, vous devez en créer une nouvelle instance au lieu de simplement le modifier. Cela peut aider à garantir la stabilité de l'application et faciliter le débogage et le développement.

Le cœur du projet se trouve dans la classe **`State`**. Cette classe définit la structure de l'état global et implémente les méthodes pour ajouter, supprimer et gérer les écoutes pour les mutations de l'état. La classe **`States`** est utilisée pour créer et gérer les instances de la classe **`State`**.

L'API publique du projet est la fonction **`useState`**, qui permet de créer un nouvel état global. L'utilisation de **`useState`** est similaire à celle de la fonction **`useState`** dans React, vous pouvez spécifier une valeur initiale pour l'état et obtenir une référence à la valeur actuelle de l'état ainsi qu'une fonction pour mettre à jour la valeur.

## **Explication**

### **Classe `State`**

La classe **`State`** est la classe principale pour gérer l'état global de l'application. Elle définit une propriété **`value`** qui représente la valeur actuelle de l'état. La propriété **`value`** est définie en utilisant la notation de private field, ce qui signifie qu'elle ne peut pas être directement accédée en dehors de la classe **`State`**.

La méthode **`addMutationListener`** est utilisée pour ajouter une écoute pour les mutations de l'état. Elle accepte un élément HTML de référence et une fonction de rappel en tant que paramètres et renvoie un identifiant d'abonnement unique qui peut être utilisé pour supprimer l'écoute plus tard. L'identifiant d'abonnement est généré en utilisant la fonction **`crypto.randomUUID`**.

La méthode **`removeMutationListener`** est utilisée pour supprimer une écoute pour les mutations de l'état en utilisant l'identifiant d'abonnement. Si l'identifiant d'abonnement n'existe pas, la méthode ne fait rien.

#### **La méthode mutator**

La méthode **`mutator`** est utilisée pour obtenir une référence à la valeur actuelle de l'état ainsi qu'une fonction pour mettre à jour la valeur. Cette méthode retourne un tableau contenant deux éléments : un premier élément qui est une référence à l'instance **`State`** en cours, et un second élément qui est une fonction **`(value) => { ... }`** qui peut être utilisée pour mettre à jour la valeur de l'état.

Lorsque cette fonction de mise à jour est appelée, elle appelle d'abord la méthode privée **`#_mutationCallback`** pour déclencher les callbacks d'écoute des mutations, puis elle retourne la valeur mise à jour en appelant la méthode privée **`#_update`**. Cette dernière méthode met à jour la valeur interne **`#_value`** et la retourne.

#### **Les callbacks d'écoute des mutations**

Les callbacks d'écoute des mutations sont des fonctions qui sont enregistrées avec la méthode **`addMutationListener`** et qui seront appelées chaque fois que la valeur de l'état sera mise à jour. Cette méthode retourne un identifiant unique qui peut être utilisé pour retirer le callback d'écoute à l'aide de la méthode **`removeMutationListener`**.

Les callbacks d'écoute des mutations sont stockés dans la propriété privée **`#_mutation_callback_stack`** qui est un objet de type **`Map`**. Cet objet stocke les callbacks en associant une clé (l'identifiant unique retourné par **`addMutationListener`**) à un objet qui définit la cible (l'élément HTML) et la fonction de callback.

Avant d'appeler les callbacks, la méthode **`#_mutationCallback`** vérifie si la cible est toujours présente dans le document en utilisant la méthode **`contains`** de l'objet **`ownerDocument`**. Si la cible n'est plus présente, le callback correspondant est retiré de la pile en utilisant **`delete`**.

### **Utilisation avec la fonction `useState`**

La fonction **`useState`** est une fonction d'aide qui permet d'obtenir une référence à un état en utilisant une syntaxe simple et concise. Cette fonction retourne un tableau contenant une référence à l'instance **`State`** et une fonction pour mettre à jour la valeur. La fonction peut être appelée avec un argument qui définit la valeur initiale de l'état.

La fonction **`useState`** utilise une instance de la classe **`States`** pour gérer les états. La classe **`States`** utilise un Map pour stocker les différents états avec leurs valeurs respectives. La fonction **`useState`** ajoutera une nouvelle instance de la classe **`State`** à ce Map et retournera la valeur de **`State`** et la fonction mutatrice pour mettre à jour la valeur.

En résumé, la classe **`State`** permet de gérer les états de manière centralisée et de déclencher des actions lorsque la valeur d'un état change, tandis que la fonction **`useState`** facilite l'ajout et la gestion des états.

# **Exemples**

## Exemple d'utilisation de `useState`

```typescript
const [state, setState] = useState('Initial Value');
console.log(state.value); // Affiche 'Initial Value'
setState('New Value'); // Met à jour la valeur de l'état
```

## Exemple d'ajout et de suppression d'observateurs de mutation

```typescript
const divElement = document.getElementById('myDiv');
const mutationListenerId = state.addMutationListener(divElement, (value) => {
  console.log('State changed to:', value);
});

// Pour supprimer l'observateur de mutation plus tard
state.removeMutationListener(mutationListenerId);
```

## Exemple de suppression d'un état

```typescript
const [state, setState] = useState('Initial Value');
console.log( 'State deleted:', state.delete() );

```