Est-ce possible sans Redux?

Aujourd'hui, vous pouvez trouver beaucoup de postes où réagir / redux est requis. React est super, aucune question n'est posée. La question pour Redux est de savoir si c'est possible sans lui. Si vous cherchez un peu sur Google, il y a un article solide sur Habré , où l'auteur pose la même question. Dans un article avec un exemple simple (todoList), la méthode this.updateViews () est appelée trop souvent (sept à huit fois) et cela semble plus facile à faire.

L'idée principale ici est les modèles observables, réagir est responsable de l'observable, il ne reste plus qu'à créer un modèle.

Avant de créer le modèle, quelques mots sur la conception (architecture) du client:

index - données brutes
histoire - tableau [modèle]
observateur - modèle
vue - erreurs, focus, drapeaux

index.jsx - point d'entrée du programme pour l'écran utilisateur. Index rend tous les composants avec des données par défaut, effectue des requêtes asynchrones, redessine les composants avec de nouvelles données.

// index.jsx <History> <Observer> <HeaderView /> <MainView /> </Observer> </History> 

Observer.jsx est responsable de la synchronisation du modèle pour plusieurs vues. Par exemple, Petya remplit un formulaire d'offre et voit un aperçu en temps réel dans l'en-tête de la page. Observer stocke l'objet modèle, fournissant api: onModelChange (champ, valeur) aux composants enfants.

History.jsx est une pile d'objets de modèle, où api: commit et rollback.

Model.js est ce que l'utilisateur peut saisir avec des stylos, c'est-à-dire le plus précieux. Les autres données du modèle n'ont pas besoin d'être stockées. Le modèle n'est pas un composant React, mais une classe js régulière.

 class Model { constructor(other = {}) {} // copy constructor (and default too) isEqual(other) {} // operator == less(other) {} // operator< swap(other) {} hash() {} fieldNameConstrains() {} //see below please } 

Le constructeur de copie est au moins nécessaire pour l'historique. La méthode isEqual est destinée aux modifications non enregistrées (ce qui est beaucoup plus pratique que l'indicateur en état). La méthode fieldNameConstrains est destinée aux champs dépendants.

En gros, s'il y a des champs dépendants, ils doivent être modifiés tous de suite.

 class Model { // constrains // distance <== velocity * time velocityConstrains(newVelocity) { this.velocity = newVelocity; this.distance = this.velocity * this.time; } timeConstrains(newTime) { … } distanceConstrains(newDistance) { this.distance = newDistance; this.time = this.distance / this.velocity; } } 

Par expérience personnelle, quelque chose comme model.field.onchange ne fonctionne pas, car parfois vous devez appeler le constructeur de copie et les événements onchange ne sont pas du tout nécessaires.

View.jsx

 class View extends React.Component { state = { errors: {}, focus: {}, … } render() { … <input value={this.props.model.title} onChange={e => this.props.onModelChange('title', e.target.value)} /> … } } 

Validation La validation n'a pas besoin d'être effectuée dans le modèle. Cela doit être fait en vue (n'oubliez pas que la vue est l'écran de l'utilisateur et que tout le modèle ne peut pas être affiché à l'écran). Les validateurs sont un ensemble de prédicats. Il n'y a que deux algorithmes de validation: 1) nous trouvons toutes les erreurs dans le formulaire ou 2) nous trouvons la première erreur. Par exemple

 class View extends React.Component { onClickSaveButton() { const mapper = { title: () => model.title.length && !maxLenValidator(model.title, 25), price: () => !(model.price % 40 == 0), url: () => !urlValidator(model.url), … } const errors = map(mapper, (validator, key) => { return validator() ? key : undefined; }).filter(Boolean); } //       

Droits d'accès. L'essentiel ici est de rester et de ne pas utiliser l'héritage. L'idée est que le modèle contient tous les champs et que nous coupons les champs pour les rôles. Autrement dit, il s'agit d'une liste blanche, les champs restants dans le modèle restent par défaut. Une étape est ajoutée pour la validation - nous faisons une projection de l'objet de validation (c'est aussi le mappeur, voir ci-dessus), c'est-à-dire que nous validons uniquement les champs nécessaires.

A propos de la production. Cette approche tourne en production depuis un an maintenant - c'est une interface pour créer des campagnes publicitaires, y compris des bannières. Formes de complexité variable - allant d'un modèle à l'écran, se terminant par de nombreux modèles de différents types. Ici, vous pouvez ajouter que le backend aime envoyer des structures imbriquées, vous ne devriez pas être timide et ne stocker que des structures plates dans la vue.

À propos de la méthode du modèle isEqual. Quelque part dans utils.js, il y aura des méthodes isEqual et isEqualArray:

  function isEqual(left, right) { return left.isEqual(right); } isEqualArray(v1, v2) { if (v1.length !== v2.length) { return false } for (var k = 0; k != v1.length; k++) { if (!isEqual(v1[k], v2[k])) { return false; } } return true; } 

Vous devez essayer de ne pas imbriquer de modèles. N'oubliez pas que le modèle est une donnée utilisateur et non une structure de données.

Références:

Horaires
Deux

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


All Articles