Cet article explique comment créer un gestionnaire d'état (state manager) pour partager des données entre plusieurs composants RiotJS.
Avant de commencer, assurez-vous d'avoir une application de base Riot, ou lisez mes articles précédents. Je suppose que vous avez une compréhension fondamentale de Riot ; cependant, n'hésitez pas à vous référer à la documentation si nécessaire : https://riot.js.org/documentation/
Il existe trois méthodes pour partager des données entre composants :
- Utiliser les propriétés Riot (props) pour passer des valeurs à un composant enfant. Le composant enfant doit émettre des événements vers le composant parent si une action se produit, comme un clic ou un changement d'entrée. Dans ce cas, la portée de communication est limitée : du composant parent vers l'enfant et de l'enfant vers le parent.
- Utiliser un émetteur d'événements comme Mitt, un modèle de messagerie appelé Pub/Sub, en savoir plus dans mon article précédent.
- Dernière méthode : un gestionnaire d'état : Un état global partagé et accessible par tous les composants. Dans d'autres frameworks frontaux, vous avez peut-être entendu parler de Pinia pour Vuejs ou Redux pour React. Pour RiotJS, le gestionnaire d'état est riot-meiosis.
Meiosis est un modèle de gestionnaire d'état utilisant des flux (streams) pour communiquer des valeurs, avec le principe de rendre l'utilisation très simple. Extrait de la documentation Meiosis :
L'idée est d'avoir un objet unique, de niveau supérieur, qui représente l'état de votre application, et d'avoir une manière simple de mettre à jour cet état. Les vues sont rendues en fonction de l'état et déclenchent des actions pour mettre à jour l'état. C'est tout !
Riot-meiosis reproduit ce modèle et est dédié à RiotJS. Cet article montre comment l'utiliser. L'objectif est de :
- Étape 1 : Créer un gestionnaire d'état global
- Étape 2 : Sur la page d'accueil de l'application Riot, afficher une carte accueillant une personne avec son prénom et son nom.
- Étape 3 : Afficher un dialogue pour modifier le prénom et le nom.
- Étape 4 : Sauvegarder les nouvelles valeurs dans l'état global
Configuration de Riot Meiosis
Commencez par installer le package NPM dans votre projet Riot/Vite :
npm i --save @riot-tools/meiosis
Ensuite, créez un fichier store.js, qui sera l'état global :
import { RiotMeiosis } from '@riot-tools/meiosis';
const state = {
firstname : 'Jon',
lastname : 'Snow',
firstnameEdit : '',
lastnameEdit : '',
displayForm : false
}
/** Create the state manager instance */
const stateManager = new RiotMeiosis(state, { flushOnRead: false, statesToKeep: 1 });
/** Extract the state stream **/
const { stream } = stateManager;
/** Add Root state reducer: merge the old and new state objects */
stream.addReducer((newState, oldState) => {
// Object oldState { firstname: "John", lastname: "Wick", firstnameEdit: "", lastnameEdit: "", email: "", displayForm: false }
// Object newState { displayForm: true }
return {
...oldState,
...newState
}
});
export default {
/** Simplifying the connect function for components */
connect: function (component) {
return stateManager.connect((globalState, ownState) => ({ ...ownState, ...globalState }))(component)
},
/** Provides the dispatch function to update values */
dispatch: stateManager.dispatch
};
Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/store.js
Détails du code :
- Un réducteur est créé pour fusionner l'état global avec les nouvelles valeurs provenant de tous les composants.
- Pour connecter le composant à l'état global, le composant Riot doit être enveloppé avec la fonction
store.connect()
, et passer un composant et une fonction de fusion comme argument : cela fusionnera l'état du composant avec l'état global. Pour chaque composant, l'état global est accessible avec l'expressionthis.state.value
. - Le store renvoie la
connexion
et la fonctiondispatch
utilisée pour mettre à jour les valeurs. - L'état global est initialisé avec un prénom et nom, un second prénom et nom pour les entrées du dialogue afin de modifier le profil, et un booléen
displayForm
pour afficher le dialogue.
Écrivez le code HTML dans c-welcome-card.riot, et connectez le Store au composant:
<c-welcome-card>
<article class="no-padding border round">
<img class="responsive small top-round" src="./examples/data/img-card.png">
<div class="padding">
<h5>Welcome</h5>
<p>Bonjour <b>{ state.firstname} { state.lastname }</b> 👋 to our app! We're excited to have you here.Whether you're in finance, marketing, or operations, our app delivers the insights you need to drive growth and stay ahead of the competition.</p>
<nav>
<button onclick={ editProfile }>Edit Profile</button>
</nav>
</div>
</article>
<script>
import store from "./store.js";
export default store.connect({
editProfile () {
store.dispatch({
displayForm: true,
firstnameEdit: this.state.firstname,
lastnameEdit: this.state.lastname,
})
}
})
</script>
</c-welcome-card>
Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-welcome-card.riot
Détails du code :
- Le Store est chargé, et le composant est connecté avec
store.connect()
. - Pour mettre à jour l'une des valeurs du magasin global, appelez la fonction
store.dispatch()
. - Lorsque le bouton est cliqué, la fonction
editProfile()
est déclenchée pour afficher le dialogue et définirfirstnameEdit
etlastnameEdit
.
Créez un fichier nommé c-form.riot, et connectez le Store pour accéder aux valeurs firstnameEdit
et lastnameEdit
. Il sera utilisé pour les inputs:
<c-form>
<c-dialog active={ state.displayForm } oncancel={ close } onconfirm={ confirmEdit }>
<template slot="body">
<h5 style="margin-bottom:30px">Edit Profile</h5>
<c-input value={ state.firstnameEdit } onkeyup={ (ev) => updateInput(ev, 'firstnameEdit') } onchange={ (ev) => updateInput(ev, 'firstnameEdit') } outlined="true" round="true" placeholder="Firstname" />
<c-input value={ state.lastnameEdit } onkeyup={ (ev) => updateInput(ev, 'lastnameEdit') } onchange={ (ev) => updateInput(ev, 'lastnameEdit') } outlined="true" round="true" placeholder="Lastname" />
</template>
</c-dialog>
<script>
/** State manager **/
import store from './store.js';
/** Components **/
import cInput from '../../components/c-input.riot';
import cButton from '../../components/c-button.riot';
import cDialog from '../../components/c-dialog.riot';
export default store.connect({
components: {
cInput,
cButton,
cDialog
},
close() {
store.dispatch({ displayForm: false })
},
updateInput(ev, keyName) {
store.dispatch({ [keyName]: ev?.target?.value ?? '' })
},
confirmEdit() {
store.dispatch({
displayForm: false,
firstname: this.state.firstnameEdit,
lastname: this.state.lastnameEdit
})
}
});
</script>
</c-form>
Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/c-form.riot
Détails du code :
- Trois composants personnalisés sont chargés : un Input, un Dialog, et un bouton.
- Le dialogue affiche deux composants d'entrée pour mettre à jour
firstnameEdit
etlastnameEdit
. - Si le bouton confirmer est cliqué, les nouvelles valeurs sont sauvegardées dans l'état global firstname et lastname grâce à la fonction
store.dispatch
. La carte de bienvenue reçoit la mise à jour ; le prénom et le nom sont rafraîchis.
Pourquoi utiliser firstnameEdit/lastnameEdit et non directement firstname/lastname ? Lorsqu'un utilisateur saisit de nouveaux noms, il peut annuler à tout moment l'édition sans affecter firstname/lastname. Le changement de valeur ne prend effet que lorsqu'un bouton confirmer est cliqué.
Maintenant, nous pouvons charger les deux composants dans un fichier commun index.riot:
<index-riot>
<div style="width:400px;padding:40px;">
<c-welcome-card />
<c-form />
</div>
<script>
import cForm from "./c-form.riot"
import cWelcomeCard from "./c-welcome-card.riot"
export default {
components: {
cForm,
cWelcomeCard
}
}
</script>
</index-riot>
Code Source: https://github.com/steevepay/riot-beercss/blob/main/examples/meiosis/index.riot
Les deux composants sont indépendants, ne communiquant que par le gestionnaire d'état global.
Conclusion
Un gestionnaire d'état est très puissant pour lire et mettre à jour des données entre les composants Riot. Les données peuvent être des listes, des objets ou des cartes. Le magasin peut être connecté à un nombre illimité de composants pour de grandes applications frontales de production réalisées avec RiotJS !
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.