L'autre jour, quelqu'un que je connais m'a envoyé un message :
"Je me suis retrouvé pendant les vacances à essayer d'expliquer à mon fils comment fonctionnaient les retours sur investissement sur Zoom et cela aurait été si simple si nous avions tous les deux pu travailler dans quelque chose comme un document Google"
Défi accepté !
Ces derniers jours, je me suis amusé à construire un simulateur de retour sur investissement, où l'on peut prévoir les retours sur investissement en fonction de plusieurs paramètres.
Internet regorge de sites Web de ce type, mais dans celui-ci, je voulais explorer comment nous pouvons intégrer des fonctionnalités collaboratives et comment elles peuvent rassembler les gens.
Dans ce guide, nous verrons comment ajouter une collaboration en temps réel à une application React classique en seulement 10 minutes sans écrire de code backend ni gérer de sockets Web. En prime, nous explorerons également comment nous pouvons améliorer l'expérience utilisateur sur les sites Web collaboratifs !
Le code source complet de ce projet est disponible sur GitHub
Plongeons-nous !
Avant de nous plonger dans les fonctionnalités collaboratives, il nous fallait une base solide. J'ai commencé par créer une version solo où les utilisateurs pouvaient saisir leurs paramètres d'investissement. Ces entrées alimenteraient ensuite un moteur de calcul qui génère et affiche des prévisions de retour sur investissement.
J'ai utilisé bolt.new pour être opérationnel rapidement. J'ai été impressionné par le design épuré qu'il m'a offert et par la rapidité avec laquelle je suis arrivé à un point de départ acceptable. Malgré l'énorme longueur d'avance, j'avais encore besoin d'affiner une certaine logique de calcul et d'ajuster l'interface utilisateur à mon goût.
Une fois la version solo terminée, je me suis concentré sur la rendre collaborative. Ce projet représentait une opportunité parfaite pour tester React Together, une bibliothèque open source que je développe chez Multisynq depuis quelques mois.
React Together fournit des hooks et des composants qui permettent des fonctionnalités collaboratives sans la complexité de la configuration des backends ou de la gestion des connexions socket. Le processus de mise en œuvre s'est avéré simple, même s'il a révélé certains domaines à améliorer que nous aborderons dans les futures versions de la bibliothèque.
Maintenant, passons en revue les trois étapes pour ajouter la collaboration en temps réel à notre application ! Démarrer vos chronomètres ?
La première étape consiste à envelopper notre application dans un fournisseur de contexte React Together. Ce composant gère toute la synchronisation de l'état et la gestion des sessions en coulisses.
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
React Together utilise l'infrastructure de Multisynq pour la synchronisation des applications, qui nécessite une clé API. Vous pouvez obtenir votre clé API gratuite sur multisynq.io/account. Et ne vous inquiétez pas, ces clés sont censées être publiques, puisque vous pouvez contrôler quels domaines peuvent les utiliser.
Nous pourrions configurer React Together pour connecter automatiquement tous les utilisateurs à la même session une fois qu'ils accèdent au site Web. En fait, cela en ferait un guide en 2 étapes, mais j'ai opté pour une approche de type Google Docs où la collaboration est facultative. Les utilisateurs restent déconnectés jusqu'à ce qu'ils créent ou rejoignent explicitement une session en cliquant sur un bouton. Nous aborderons la gestion des sessions dans la troisième étape de ce guide !
Une fois React Together configuré, l'étape suivante consiste à synchroniser l'état entre les utilisateurs. Ce processus est incroyablement simple : il suffit de remplacer les hooks useState de React par les hooks useStateTogether de React Together.
Le hook useStateTogether fonctionne de la même manière que useState, mais nécessite un paramètre rtKey supplémentaire. Cette clé identifie de manière unique l'état dans l'application, garantissant une synchronisation appropriée même dans les mises en page réactives où les hiérarchies DOM peuvent différer entre les fenêtres.
Voici à quoi ressemble la transformation :
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
// Before import { useState } from 'react' export default function Calculator() { const [startingAmount, setStartingAmount] = useState(20000); const [years, setYears] = useState(25); const [returnRate, setReturnRate] = useState(10); const [compoundFrequency, setCompoundFrequency] = useState("annually"); const [additionalContribution, setAdditionalContribution] = useState(500); const [contributionTiming, setContributionTiming] = useState("beginning"); const [contributionFrequency, setContributionFrequency] = useState("month"); // ... }
La beauté de cette approche est que l'application continue de fonctionner exactement comme avant - la seule différence est que désormais les mises à jour d'état sont synchronisées pour tous les utilisateurs connectés.
La dernière étape consiste à ajouter un moyen permettant aux utilisateurs de créer, rejoindre et quitter des sessions collaboratives. J'ai choisi de l'implémenter via une section d'en-tête au-dessus de la calculatrice, rendant les contrôles de session facilement visibles par tout le monde.
React Together simplifie les choses en fournissant quatre accroches essentielles :
Voici une version simplifiée du composant header (je viens de supprimer les noms de classes) :
// After import { useStateTogether } from 'react-together' export default function Calculator() { const [startingAmount, setStartingAmount] = useStateTogether("startingAmount", 20000); const [years, setYears] = useStateTogether("years", 25); const [returnRate, setReturnRate] = useStateTogether("returnRate", 10); const [compoundFrequency, setCompoundFrequency] = useStateTogether("compoundFrequency", "annually"); const [additionalContribution, setAdditionalContribution] = useStateTogether("additionalContribution", 500); const [contributionTiming, setContributionTiming] = useStateTogether("contributionTiming", "beginning"); const [contributionFrequency, setContributionFrequency] = useStateTogether("contributionFrequency", "month"); // ... }
Avec cette implémentation, les utilisateurs peuvent désormais démarrer des sessions collaboratives d'un simple clic. Lorsqu'une personne rejoint l'équipe en utilisant l'URL partagée, elle voit immédiatement le même état que tout le monde, avec toutes les modifications synchronisées en temps réel pour tous les participants.
Et voilà, c'est facile et ça marche ! De plus, vous pouvez le faire en moins de 10 minutes !!
Bien que la synchronisation de base fonctionnait bien, quelque chose n'allait pas : les éléments changeaient "par eux-mêmes" sur la page, sans aucune indication de qui effectuait les modifications. Il s'agit d'un défi courant dans les applications collaboratives, et des outils tels que Google Docs le résolvent en montrant où les autres utilisateurs consultent et modifient.
La véritable collaboration ne consiste pas seulement à synchroniser l'état, il s'agit également de créer un sentiment de présence. Les utilisateurs doivent se « voir » pour travailler ensemble efficacement.
J'ai initialement envisagé d'implémenter des curseurs partagés, permettant aux utilisateurs de voir les pointeurs de souris des autres. Cependant, cette approche présente des défis dans les applications Web réactives :
Au lieu de cela, je me suis concentré sur ce que nous voulons vraiment réaliser avec la présence des utilisateurs :
La solution ? Mettez en surbrillance les éléments avec lesquels les utilisateurs interagissent. Cette approche est plus simple, plus intuitive et fonctionne de manière fiable dans toutes les tailles de fenêtre. Voyons comment mettre en œuvre cela dans deux domaines clés : les onglets du graphique et les champs de saisie.
Commençons par une implémentation simple de la présence des utilisateurs : montrer quels utilisateurs consultent chaque onglet du graphique.
Pour cela, nous avons besoin d'un type spécial d'état partagé où chaque utilisateur peut avoir sa propre valeur visible par tous les autres.
React Together fournit exactement ce dont nous avons besoin avec le hook useStateTogetherWithPerUserValues (oui, c'est toute une bouchée !). Ce hook fonctionne de manière similaire à useStateTogether, mais au lieu de partager une valeur unique, il permet à chaque utilisateur d'avoir sa propre valeur visible par tous les participants. Le hook renvoie trois éléments :
Voici comment nous implémentons cela pour afficher les avatars des utilisateurs à côté des onglets :
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
Dans l'extrait de code ci-dessus, nous avons remplacé un useState par un useStateTogetherWithPerUserValues, et encore une fois, l'application a continué à fonctionner comme avant, mais maintenant tout le monde pouvait voir l'état de chacun ! Ensuite, il nous suffisait de restituer les nouvelles informations que nous venions de recevoir.
Cette implémentation affiche les avatars des utilisateurs à côté de chaque onglet, indiquant clairement quels utilisateurs consultent quels graphiques. Nous filtrons l'avatar de l'utilisateur actuel pour éviter la redondance, car les utilisateurs n'ont pas besoin de voir leur propre indicateur de présence.
L'ajout d'indicateurs de présence aux champs de saisie suit un modèle similaire à l'exemple précédent, mais avec une exigence supplémentaire : nous devons suivre le moment où les utilisateurs commencent et arrêtent la modification. Heureusement, les composants d'Ant Design fournissent les rappels nécessaires à cet effet.
Pour chaque champ de saisie, je voulais :
Voici comment nous implémentons cela à l'aide du hook useStateTogetherWithPerUserValues :
// src/index.tsx import { StrictMode } from 'react' import { ReactTogether } from 'react-together' import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' createRoot(document.getElementById('root')!).render( <StrictMode> <ReactTogether sessionParams={{ appId: import.meta.env['VITE_APP_ID'], apiKey: import.meta.env['VITE_API_KEY'], }}> <App /> </ReactTogether> </StrictMode>, )
Bien que le code soit légèrement plus long, le principe est simple : il nous suffit de suivre quels utilisateurs modifient chaque champ de saisie, puis de restituer la visualisation de notre choix.
Cette même approche fonctionne pour tout autre type d'entrée, tel que les listes déroulantes et les barres de défilement !!
--
Et c'est tout ! Avec ce simulateur de retour sur investissement entièrement collaboratif, il sera plus facile pour mon ami d'expliquer à son fils comment les retours sur investissement fonctionnaient sur Zoom. Mission accomplie ! ✨
En voyant à quel point il est facile de créer ce genre de site collaboratif, je me demande comment Internet peut nous rapprocher lorsque nous sommes en ligne... Nous en reparlerons plus tard !
J'espère que vous avez appris quelque chose de nouveau et n'hésitez pas à nous contacter si vous avez des commentaires ou des questions !!
Bon codage ! ?
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!