Dans cet article, nous allons explorer la dernière API proposée par l’équipe de VueJS : Composition API. Cette dernière devrait être incluse dans la version 3 et utilisable dans la version 2.x via un package (gérer par la core team de VueJS).

Cette API n’a pas pour but de remplacer l’API basée sur les objets littéraux présente dans la version 2.x de VueJS mais de vivre et évoluer en parallèle.

Historique

Fin de l’année 2018, il est annoncé que la version 3 de Vuejs sera entièrement réécrite en TypeScript. Cela ne doit pas affecter les projets écrit en JavaScript, mais doit permettre un bien meilleur support de TypeScript. L’objectif visé est donc d’utiliser au maximum la capacité de déduction (inférence) de type du compilateur. Cela nécessite d’écrire des fichiers de définition pour typer l’API déjà existante (.d.ts).

L’API actuelle de VueJS (2.x) permet de créer des composant via des objets littéraux qui sont composés de propriétés spéciales (data, computed, methods, …) contenant elles-mêmes des objets ou des fonctions. Ces propriétés spéciales sont ensuite fusionnées afin de résoudre le this qui permet d’accéder aux données et fonctions exposées par le composant.

Exemple :

1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
name: "Counter",
data: function() {
return {
localState: 1
};
},
methods: {
increment: function() {
this.localState++; // grâce au merge, this accède aux propriétés de l'objet retourné par la propriété data
}
}
};

Cette API basée sur les objets littéraux est très peformante mais complique l’inférence de type. La magie de résolution du this ce fait alors de l’exécution du programme alors que les types de TypeScript ne sont utiles qu’a la compilation. C’est pour cette raison qu’en février 2019, l’équipe s’oriente vers une nouvelle API : Class API.

Exemple :

1
2
3
4
5
6
7
class Counter extends Vue {
localState = 1;

increment() {
this.localState++;
}
}

Elle propose d’utiliser des classes pour déclarer ses composants. Malheureusement la Class API se révèle également complexe à typer et à implémenter… De plus l’équipe de VueJS, ne souhaite pas se reposer sur les décorateurs qui ne sont pas encore standardisé au sein de la norme ECMAScript (stage 2. Elle est donc finalement abandonnée en mai 2019 pour une nouvelle API : Function-based Component API.

Exemple :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { reactive, createComponent } from 'vue'

export default createComponent({
name: 'Counter',
setup() {

const localState = reactive({
count: 0
});

const increment = () => {
localState.value++;
};

},
});

Celle-ci a une approche radicalement différente et se repose sur un principe lié à la programmation fonctionnel : la composition. Elle sera finalement révisée puis renommée Composition API.

Le projet Vuejs possède un dépôt permettant de soumettre des Request For Comments (RFCs). C’est donc par le biais de ce process que sont proposées, discutées puis ajoutées les nouvelles APIs/fonctionnalités du Framework. N’hésitez pas à y faire un tour :)

Composition API ?

La Composition API permet de créer/exporter des fonctions qui pourront être réutilisées à travers différents composants. Elle a pour objectif de facilité grandement la composition et la réutilisation. De plus, les fonctions sont très faciles à inférer ce qui facilite donc le passage sur TypeScript.

En VueJS 2.x, pour partager de la logique entre plusieurs composants, il existe déjà les Mixins, les HOC (High Order Component) et les renderless components. Malheureusement, ces derniers possèdent plusieurs inconvénients :

  • Difficulté à identifier l’origine des propriétés utilisées dans la partie template d’un composant.
  • Collisions de nom de propriété.
  • Coût d’instanciation supplémentaire pour les HOC et les renderless compoenent.

La Composition API résout de façon élégante ces inconvénients :

  • Identification claire de l’origine des propriétés car elles proviennent de fonction nommées.
  • Possibilité de nommer de façon arbitraire les valeurs retournées par une fonction afin d’éviter les collisions de noms.
  • Pas de coût d’instanciation supplémentaire.

Autre grand changement : l’organisation du code. Avec l’API existante de VueJS 2.x, le code d’une fonctionnalité d’un composant se retrouve partagé entre les propriétés spéciales data (son état), méthods (manipulation de son état), … Cela complexifie la lecture du code. Avec la Composition API le code doit être regroupé par fonctionnalités comme l’illustre le schéma ci-dessous :

schema option API vs composition API

Exemple sans Composition API :

1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
name: "Counter",
data: function() {
return {
localState: 1
};
},
methods: {
increment: function() {
this.localState++;
}
}
};

Exemple avec Composition API :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ref } from 'vue'

export function useCounter(start) {
const counter = ref(start);

function increments() {
counter++;
}

return {
counter,
increments
};
}

Dans l’exemple ci-dessus, la fonction useCounter peut-être importée puis utilisée dans n’importe quel composant pour créer puis incrémenter un compteur.

A quoi ça ressemble ?

La Composition API expose des fonctionnalités normalment utilisées par le coeur de VueJS. Voici un exemple :

Fichier counter.ts :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ref } from 'vue'

export function useCounter(start) {
const counter = ref(start);

function increments() {
counter++;
}

return {
counter,
increments
};
}

Fichier counterComponent.ts :

1
2
3
4
5
6
7
8
9
import { createComponent } from 'vue'
import { useCounter } from './counter'

createComponent({
name: 'Counter',
setup() {
const { counter, increments } = useCounter()
}
}

La fonction createComponent est indispensable pour avoir une parfaite inférence au sein d’un composant. La fonction setup est un hook utilisé pour composer le composant. Il est possible de retourner un objet dont les propriétés éxposées seront disponible dans les différentes propriétés spéciales proposées par l’API 2.x (data, methods, computed, …).
La fonction ref permet de surveiller les changements d’une propriété primitive. Elle pourra être utilisée dans un template et celui-ci sera mis à jour si la valeur de la propriété change. Pour surveiller les changements d’une propriété de type object, la fonction reactive sera utilisée.

Si vous souhaitez jouer avec la Composition API n’hésitez pas à utiliser le package compatible avec la version 2.x de VueJS en local ou directement online sur CodeSandbox par exemple ^^

Bonne journée et à bientôt !