Ajouter une galerie d’images à RichTextEditor avec React

La boîte de dialogue Insert Gallery de l’exemple Vite + React, qui liste les dossiers blog, products et team et quatre images du serveur Express

La boîte de dialogue Insert Gallery de RichTextEditor fonctionne de la même façon dans une application React que sur une page simple. Ce qui change, c’est le câblage : l’éditeur est un script navigateur que React ne gère pas, le composant doit le nettoyer, et pendant le développement les requêtes de la boîte de dialogue doivent atteindre votre serveur d’API en passant par le serveur de développement. Cette page présente une configuration Vite + React qui fait ces trois choses, testée avec l’exemple Express.

Charger les scripts de l’éditeur avant l’application

L’éditeur est fourni sous forme de scripts simples qui définissent window.RichTextEditor. Dans une application Vite, l’endroit correct le plus simple pour eux est index.html, avant le script de module qui démarre React :

HTML · index.html
<!-- Plain browser scripts from public/, loaded before the React bundle. -->
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css">
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<script src="/rte-files.js"></script>

Les fichiers se trouvent dans public/richtexteditor/, que Vite sert tel quel. rte-files.js relie les hooks d’envoi de l’éditeur à /rte/upload. Sans lui, la galerie peut parcourir les dossiers, mais son bouton Upload n’a rien à appeler. Les scripts classiques placés dans <head> s’exécutent avant le bundle de modules : window.RichTextEditor existe donc au moment où un composant se monte.

Le composant

JavaScript · src/RichTextEditor.jsx
// window.RichTextEditor comes from the scripts in index.html.
export default function RichTextEditor({ options, initialHtml = "", editorRef }) {
  const container = useRef(null);

  useEffect(() => {
    const editor = new window.RichTextEditor(container.current, options);
    editor.setHTMLCode(initialHtml);
    if (editorRef) editorRef.current = editor;
    // Runs on unmount, and once in development: Strict Mode mounts, unmounts, mounts again.
    return () => {
      if (editorRef) editorRef.current = null;
      editor.destroy();
    };
  }, []); // create once; options are read at creation

  return <div ref={container} />;
}

L’éditeur est créé une seule fois, dans useEffect, sur le div désigné par la ref. Le nettoyage appelle destroy(). C’est important en développement, car le Strict Mode de React monte chaque composant, le démonte puis le monte de nouveau. Grâce au nettoyage, le premier éditeur est détruit avant la création du second. Notre vérification dans le navigateur, avec <StrictMode> activé, a trouvé exactement un éditeur sur la page, et l’avis de version d’évaluation de l’éditeur est apparu deux fois dans la console : une fois par création. Il est facile de ne pas remarquer l’absence du nettoyage. Quand nous avons créé un second éditeur sur le même div sans destroy(), la page affichait toujours un seul éditeur, mais la première instance n’a jamais été nettoyée.

La liste de dépendances vide est voulue. Les options sont lues à la création de l’éditeur : recréer l’éditeur à chaque rendu ferait donc perdre ce que l’utilisateur a tapé. Pour lire le contenu, conservez l’instance dans une ref et appelez getHTMLCode() :

JavaScript · src/App.jsx
const options = {
  toolbar: "full",
  galleryEndpoint: "/rte/gallery", // forwarded to Express by vite.config.js
  maxUploadFileSize: 4000000,
};

Dans l’exemple, un bouton Show HTML appelle editor.current.getHTMLCode() et a affiché <p>Hello from React.</p>. Après l’insertion d’une image depuis la galerie, le HTML contient <img src="/uploads/...">.

Atteindre le serveur d’API en développement

galleryEndpoint: "/rte/gallery" est relatif à la page, et la page vient de Vite. Le proxy de développement de Vite transmet /rte/ (les routes de galerie et d’envoi) et /uploads/ (les images) à l’exemple Express sur le port 5101 :

JavaScript · vite.config.js
// /rte/ and /uploads/ go to the Express sample (node-express, port 5101).
// Keep the trailing slashes: "/rte" alone would also catch /rte-files.js.
proxy: {
  "/rte/": "http://localhost:5101",
  "/uploads/": "http://localhost:5101",
},

Le navigateur ne voit qu’une seule origine : il n’y a donc ni en-têtes CORS à définir ni URL absolues dans les options de l’éditeur. Conservez les barres obliques finales. Vite compare une clé simple comme préfixe de l’URL : une clé "/rte" correspond donc aussi à /rte-files.js. Nous l’avons essayé : avec "/rte", /rte-files.js est revenu avec X-Powered-By: Express, servi par le serveur d’API au lieu de l’application. Avec "/rte/", Vite a servi sa propre copie.

Le proxy est une fonctionnalité de développement. En production, servez l’application compilée et l’API depuis une même origine, par exemple avec Express qui sert dist/ à côté des routes, ou derrière un même proxy inverse.

Ce qu’affiche la boîte de dialogue

L’image en haut de la page montre la boîte de dialogue dans cette application React, avec les dossiers et les images du serveur Express. Le côté serveur est le même que dans le guide sur la galerie en Node.js. Deux limites viennent de la galerie publiée, et non de React. L’indication des formats mentionne JFIF, BMP et AVIF, que le serveur d’exemple refuse. Et un fichier refusé affiche « Upload failed for <name>. » au lieu du message du serveur.

Tester

Téléchargez le projet d’exemple de ce guide et l'exemple Express. Copiez le dossier richtexteditor du téléchargement de l’éditeur dans l’exemple Express, ou définissez RTE_DIR, puis démarrez-le avec npm install et npm start. Ensuite, dans le projet React :

Shell
npm install
npm run dev
  VITE v8.3.5  ready in 440 ms
  ➜  Local:   http://localhost:5111/

curl "http://localhost:5111/rte/gallery?folder="
{"currentFolder":"","currentFolderDisplay":"/","parentFolder":null,"folders":[...],"images":[...]}

npm run dev copie d’abord les fichiers de l’éditeur dans public/. Définissez RTE_DIR sur votre dossier de l’éditeur, ou placez vous-même le dossier dans public/richtexteditor. Ouvrez http://localhost:5111, cliquez sur Insert Gallery, choisissez une image et cliquez sur Insert.

Le même guide pour d’autres plateformes

Vue · Angular

À lire ensuite