Architecture Redux. Oui ou non?

L'auteur du matériel, dont nous publions la traduction aujourd'hui, dit qu'il fait partie de l'équipe de messagerie de Hike , qui est engagée dans de nouvelles fonctionnalités de l'application. Le but de cette équipe est de traduire dans la réalité et d'explorer des idées que les utilisateurs peuvent aimer. Cela signifie que les développeurs doivent agir rapidement et qu'ils doivent souvent apporter des modifications aux innovations qu'ils recherchent, qui visent à rendre l'expérience utilisateur aussi pratique et agréable que possible. Ils préfèrent mener leurs expériences en utilisant React Native, car cette bibliothèque accélère le développement et vous permet d'utiliser le même code sur différentes plates-formes. De plus, ils utilisent la bibliothèque Redux.



Lorsque les développeurs de Hike commencent à travailler sur quelque chose de nouveau, alors, lorsqu'ils discutent de l'architecture de la solution étudiée, ils ont plusieurs questions:

  • Il s'agit d'une opportunité expérimentale qui peut, comme on dit, «ne pas s'envoler», et elle devra être abandonnée. Compte tenu de cela, est-il nécessaire de passer du temps à concevoir l'architecture de l'application?
  • Une application expérimentale est juste un MVP, un produit minimalement viable qui a 1-2 écrans et doit être créé le plus rapidement possible. Compte tenu de cela, dois-je contacter Redux?
  • Comment justifiez-vous le temps nécessaire aux chefs de produit pour préparer l'infrastructure de support à une application expérimentale?

En fait, Redux vous aide à trouver les bonnes réponses à toutes ces questions. L'architecture Redux permet de séparer l'état de l'application de React. Il vous permet de créer un référentiel global situé au niveau supérieur de l'application et fournissant un accès à l'état pour tous les autres composants.

Séparation des responsabilités


Qu'est-ce qu'une «séparation des responsabilités»? Voici ce qu'en dit Wikipédia : «En informatique, la répartition des responsabilités est le processus de division d'un programme informatique en blocs fonctionnels qui se chevauchent le moins possible les uns les autres. Dans un cas plus général, la division des responsabilités est la simplification d'un processus unique pour résoudre un problème en le divisant en processus interactifs pour résoudre des sous-tâches. "

L'architecture de Redux vous permet de mettre en œuvre le principe de séparation des responsabilités dans les applications, en les divisant en quatre blocs, comme illustré dans la figure suivante.


Architecture de Redux

Voici une brève description de ces blocs:

  • Les représentations ou les composants d'interface utilisateur (composants d'interface utilisateur) ressemblent à des fonctions pures (c'est-à-dire les fonctions qui ne modifient pas les données qui leur sont transférées et qui ont d'autres propriétés) qui sont chargées d'afficher des informations à l'écran en fonction des données qui leur sont transférées depuis le magasin. Ils ne modifient pas directement les données. Lorsqu'un événement se produit ou si l'utilisateur interagit avec eux, ils se tournent vers les créateurs des actions.
  • Les créateurs d'actions sont responsables de la création et de la répartition des actions.
  • Les réducteurs reçoivent des actions planifiées et mettent à jour l'état du référentiel.
  • Le magasin de données est responsable du stockage des données d'application.

Jetons un coup d'œil à l'architecture Redux.

Et si différents composants ont besoin des mêmes données?


L'application Hike dispose d'un écran affichant la liste d'amis de l'utilisateur. Des informations sur leur quantité sont affichées en haut de cet écran.


Écran d'amis dans l'application Randonnée

Il y a 3 composants React ici:

  • FriendRow est un composant contenant le nom de l'ami de l'utilisateur et d'autres informations le concernant.
  • FriendsHeader - un composant qui affiche l'inscription "MES AMIS" et des informations sur le nombre d'amis.
  • ContainerView est un composant conteneur qui combine le titre d'écran représenté par le composant FriendsHeader et la liste d'amis obtenue en parcourant un tableau contenant des informations sur les amis de l'utilisateur, dont chaque élément est affiché à l'écran par le composant FriendRow .

Voici le code de friendsContainer.js pour illustrer ce qui précède:

 class Container extends React.Component {   constructor(props) {     super(props);     this.state = {       friends: []     };   }   componentDidMount() {     FriendsService.fetchFriends().then((data) => {       this.setState({         friends: data       });     });   }   render() {     const { friends } = this.state;     return (       <View style={styles.flex}>       <FriendsHeader count={friends.length} text='My friends' />       {friends.map((friend) => (<FriendRow {...friend} />)) }       </View>     );   } } 

Une façon complètement évidente de créer une telle page d'application consiste à charger des données sur des amis dans un composant conteneur et à les transmettre en tant que propriétés aux composants enfants.

Pensons au fait que ces données sur les amis peuvent être nécessaires dans certains autres composants utilisés dans l'application.


Écran de discussion de randonnée

Supposons que l'application dispose d'un écran de discussion, qui contient également une liste d'amis. On peut voir que les mêmes données sont utilisées à l'écran avec la liste d'amis et sur l'écran de chat. Que faire dans une situation similaire? Nous avons deux options:

  • Vous pouvez télécharger à nouveau les données de vos amis dans le composant ComposeChat responsable de l'affichage des listes de discussion. Cependant, cette approche n'est pas particulièrement bonne, car son utilisation entraînera une duplication des données et peut entraîner des problèmes de synchronisation.
  • Vous pouvez télécharger des données sur vos amis dans un composant de niveau supérieur (le conteneur principal de l'application) et transférer ces données aux composants chargés d'afficher une liste d'amis et de répertorier les salles de discussion. De plus, nous devons transmettre des fonctions à ces composants pour mettre à jour les données des amis, ce qui est nécessaire pour prendre en charge la synchronisation des données entre les composants. Cette approche conduira au fait que le composant de niveau supérieur sera littéralement emballé avec des méthodes et des données qu'il n'utilise pas directement.

Ces deux options ne sont pas si attrayantes. Voyons maintenant comment notre problème peut être résolu en utilisant l'architecture Redux.

Utiliser Redux


Nous parlons ici d'organiser le travail avec des données en utilisant le stockage, des créateurs d'actions, des réducteurs et deux composants de l'interface utilisateur.

▍1. Entrepôt de données


Le référentiel contient des données téléchargées sur les amis de l'utilisateur. Ces données peuvent être envoyées à n'importe quel composant en cas de besoin.

▍2. Créateurs d'action


Dans ce cas, le créateur de l'action est utilisé pour envoyer des événements visant à enregistrer et à mettre à jour des données sur des amis. Voici le code pour friendsActions.js :

 export const onFriendsFetch = (friendsData) => { return {   type: 'FRIENDS_FETCHED',   payload: friendsData }; }; 

▍3. Réducteurs


Les réducteurs attendent que des événements représentant des actions planifiées arrivent et mettent à jour leurs amis. Voici le code pour friendsReducer.js :

 const INITIAL_STATE = {      friends: [],   friendsFetched: false }; function(state = INITIAL_STATE, action) {   switch(action.type) {   case 'FRIENDS_FETCHED':       return {           ...state,           friends: action.payload,           friendsFetched: true       };   } } 

▍4. Composant de liste d'amis


Ce composant conteneur affiche les données des amis et met à jour l'interface lorsqu'ils changent. De plus, il est responsable du téléchargement des données du référentiel s'il ne les a pas. Voici le code pour friendsContainer.js :

 class Container extends React.Component {   constructor(props) {     super(props);   }   componentDidMount() {     if(!this.props.friendsFetched) {       FriendsService.fetchFriends().then((data) => {         this.props.onFriendsFetch(data);       });     }   }   render() {     const { friends } = this.props;     return (       <View style={styles.flex}>       <FriendsHeader count={friends.length} text='My friends' />       {friends.map((friend) => (<FriendRow {...friend} />)) }       </View>     );   } } const mapStateToProps = (state) => ({ ...state.friendsReducer }); const mapActionToProps = (dispatch) => ({ onFriendsFetch: (data) => {   dispatch(FriendActions.onFriendsFetch(data)); } }); export default connect(mapStateToProps, mapActionToProps)(Container); 

▍5. Composant de liste de discussion


Ce composant de conteneur utilise également les données du stockage et répond à sa mise à jour.

À propos de la mise en œuvre de l'architecture Redux


Cela peut prendre un jour ou deux pour mettre l'architecture décrite ci-dessus en état de fonctionnement, mais lorsque des modifications doivent être apportées au projet, elles sont apportées très simplement et rapidement. Si vous devez ajouter un nouveau composant à l'application qui utilise des données sur vos amis, vous pouvez le faire sans vous soucier de la synchronisation des données ou que vous devrez refaire d'autres composants. Il en va de même pour la suppression de composants.

Test


Lors de l'utilisation de Redux, chaque bloc d'application peut être testé indépendamment.
Par exemple, chaque composant d'interface utilisateur peut être facilement soumis à des tests unitaires, car il est indépendant des données. Le fait est qu'une fonction représentant un tel composant renvoie toujours la même représentation pour les mêmes données. Cela rend l'application prévisible et réduit la probabilité d'erreurs qui se produisent lors de la visualisation des données.

Chaque composant peut être testé de manière exhaustive en utilisant une variété de données. Ces tests révèlent des problèmes cachés et contribuent à garantir un code de haute qualité.

Il convient de noter que non seulement les composants responsables de la visualisation des données, mais également les réducteurs et les créateurs d'actions peuvent être soumis à des tests indépendants.

Redux est génial, mais en utilisant cette technologie, nous avons rencontré quelques difficultés.

Difficultés à utiliser Redux


▍ Code modèle excédentaire


Afin de mettre en œuvre l'architecture Redux dans une application, vous devez passer beaucoup de temps, tout en rencontrant toutes sortes de concepts et d'entités étranges.

Ce sont les soi-disant traîneaux (thunks), réducteurs (réducteurs), actions (actions), couches middleware (middlewares), ce sont les fonctions mapStateToProps et mapDispatchToProps , et bien plus encore. Il faut du temps pour apprendre tout cela et pour apprendre à l'utiliser correctement, il faut de la pratique. Il y a beaucoup de fichiers dans le projet et, par exemple, un changement mineur dans le composant pour la visualisation des données peut nécessiter d'apporter des modifications à quatre fichiers.

Le coffre de Red Redux est singleton


Dans Redux, l'entrepôt de données est construit à l'aide du modèle singleton, bien que les composants puissent avoir plusieurs instances. Le plus souvent, ce n'est pas un problème, mais dans certaines situations, une telle approche du stockage de données peut créer des difficultés. Par exemple, imaginez qu'il existe deux instances d'un composant. Lorsque les données changent dans l'une de ces instances, ces modifications affectent une autre instance. Dans certains cas, ce comportement peut ne pas être souhaitable; il peut être nécessaire que chaque instance du composant utilise sa propre copie des données.

Résumé


Rappelez-vous notre question principale, qui est de savoir s'il vaut la peine de consacrer du temps et des efforts à mettre en œuvre l'architecture Redux. En réponse à cette question, nous disons «oui» à Redux. Cette architecture permet d'économiser du temps et des efforts dans le développement et le développement d'applications. L'utilisation de Redux permet aux programmeurs d'apporter des modifications fréquentes à l'application et facilite les tests. Bien sûr, l'architecture Redux fournit une quantité considérable de code standard, mais elle aide à décomposer le code en modules qui sont pratiques à utiliser. Chacun de ces modules peut être testé indépendamment des autres, ce qui aide à identifier les erreurs au stade du développement et permet d'assurer des programmes de haute qualité.

Chers lecteurs! Utilisez-vous Redux dans vos projets?

Source: https://habr.com/ru/post/fr426473/


All Articles