Protectator

Application PixiJS v4.5 dans un Composant React

31 mai 2017 · 2 minutes
Application PixiJS v4.5 dans un Composant React

J'ai récemment commencé un nouveau projet qui utilise à la fois React et PixiJS. J'ai eu quelques difficultés à mettre les choses en place au début, et il a fallu que je fasse quelques recherches pour savoir comment utiliser correctement un renderer PixiJS dans un composant React.

En faisant ceci, j'ai découvert plusieurs librairies originales comme react-pixi qui permettent de contrôler un renderer PixiJS directement par React. Il serait probablement judicieux d'utiliser cette bibliothèque, mais je voulais mettre en place ma propre logique pour gérer le moteur de rendu de PixiJS. J'ai rencontré quelques difficultés en essayant de configurer les choses de la manière "classique" et recommandée par PixiJS. Les autres solutions que j'ai trouvées ne fonctionnent plus dans les versions récentes de PixiJS.

Comme aucune ressource ne semblait fournir une explication simple sur la façon d'utiliser correctement PixiJS dans un composant React maintenant, j'ai pensé que ce post pourrait être utile à certains.

Technologies utilisées

Avant d'aller plus loin, voici une liste des technologies que j'utilise pour ce projet. Il va de soi que je ne peux pas garantir que cela fonctionnera avec des technologies différentes ou même des versions différentes :

  • PixiJS 4.5.1
  • React 15.4.2
  • Typescript 2.1.0

Avec cela, j'utilise également d'autres librairies comme Flux ou React-Router mais elles ne sont pas pertinentes car cet article se concentre purement sur le fonctionnement d'un moteur de rendu PixiJS dans un composant React, et non sur l'architecture générale de l'application.

La manière recommandée de PixiJS

Sur les exemples visibles sur le site, la classe principale utilisée pour instancier et contrôler le moteur de rendu est d'utiliser PIXI.Application. L'exemple de code qui utilise PIXI.Application est le suivant :

// Create the application
const app = new PIXI.Application();

// Add the view to the DOM
document.getElementById('whatever').appendChild(app.view);

// ex, add display objects
app.stage.addChild(PIXI.Sprite.fromImage('something.png'));

En essayant d'imiter cela lors de l'implémentation d'un Component, on rencontre un problème. On essaie d'ajouter un élément à l'arbre DOM directement, ce qui n'est pas ce que React recommande.


Une manière typée et React

Pas de tour de magie ici, nous allons toujours devoir ajouter la vue "manuellement" pour la contrôler. Mais au lieu de référencer le DOM, nous pouvons utiliser une fonctionnalité de React appelée une Ref pour faire les choses correctement. Voici ce que la documentation nous dit :

Les refs fournissent un moyen d’accéder aux nœuds du DOM ou éléments React créés dans la méthode de rendu.

Nous allons nous en servir ici et créer un <div> qui contient un attribut ref. Nous pourrons alors interagir avec celui-ci en utilisant cette référence au lieu d'essayer d'accéder au DOM.

Plutôt que d'essayer d'expliquer trop longuement, voici le code TSX du composant dont le but est de gérer et d'afficher une instance d'une application Pixi.Application :

PixiComponent.tsx

import * as React from 'react';
import * as Pixi from 'pixi.js';

interface IMainProps {}
interface IMainState {}
export class PixiComponent extends React.Component<IMainProps, IMainState> {
  app: Pixi.Application;
  gameCanvas: HTMLDivElement;

  constructor() {
    super();
  }

  /**
   * After mounting, add the Pixi Renderer to the div and start the Application.
   */
  componentDidMount() {
    this.app = new Pixi.Application(window.innerWidth, window.innerHeight);
    this.gameCanvas.appendChild(this.app.view);
    this.app.start();
  }

  /**
   * Stop the Application when unmounting.
   */
  componentWillUnmount() {
    this.app.stop();
  }

  /**
   * Simply render the div that will contain the Pixi Renderer.
   */
  render() {
    let component = this;
    return (
      <div ref={(thisDiv) => {component.gameCanvas = thisDiv}} />
    );
  }
}

Notez que même si nous appelons appendChild nous-mêmes, nous n'avons pas utilisé ReactDOM ici. Lorsque le composant est monté, l'attribut ref appelle immédiatement notre fonction anonyme qui définit le gameCanvas sur cet élément. La fonction componentDidMount() se déclenche alors et le référence directement pour ajouter la vue Pixi.Application (qui est un Pixi.SystemRenderer).

Nous avons à présent toute possibilité de contrôler l'Application et le Renderer comme bon nous semble. Voulons-nous que l'état du jeu persiste lorsque le composant est monté/démonté ? Il suffit de sauvegarder le Pixi.Container principal dans componentWillUnmount et de le rajouter dans componentDidMount.

Conclusion

J'utilise cette méthode dans mon code et cela fonctionne très bien. Même si l'utilisation de ReactDOM et d'un attribut id serait possible, cela est enclin à des erreurs. J'aime garder les choses bien organisées et je pense que plus le compilateur est capable de vérifier de choses, mieux c'est. De plus, cela ressemble moins à un hack qu'à un composant réutilisable et autonome maintenant.

Catégorie: Développement

Commentaires