web-dev-qa-db-fra.com

Comment synchroniser les paramètres de requête d'état et d'URL de Redux

J'ai une page Web avec un panneau de recherche. Le panneau de recherche comporte plusieurs champs de saisie: id, taille, ...

Ce que je veux, c’est lorsque l’utilisateur définit les valeurs de recherche (par exemple: id = 123 et size = 45) et appuie sur un bouton de recherche:

  1. searchState dans Redux Reducer doit être mis à jour avec de nouvelles valeurs de recherche (id = 123 et size = 45)
  2. L'URL doit être remplacé par " http: // mydomain/home? Id = 123 & size = 45 "

Et d’autre part, si l’utilisateur modifie l’URL par http: // mydomain/home? Id = 111 & size = 22 alors:

  1. searchState dans le réducteur doit être modifié avec de nouvelles valeurs de recherche (id = 111 et size = 22)
  2. Les entrées du panneau de recherche d'interface utilisateur doivent être mises à jour avec les nouvelles valeurs (id = 111 et taille = 22)

Comment atteindre avec objectif? Quel routeur devrais-je utiliser (react-router, redux-router, react-router-redux ou autre)?

61
Anton

Je suggérerais simplement d'utiliser React Router directement et pas en conservant searchState dans Redux. React Le routeur injectera des paramètres d’URL dans vos composants, et vous pourrez les utiliser dans mapStateToProps(state, ownProps) pour calculer les accessoires finaux.

Si vous voulez vraiment voir les changements de route sous forme d’actions, vous pouvez utiliser react-router-redux pour la synchronisation bidirectionnelle, mais cela ne vous donnera pas les paramètres dans l’état, mais seulement l’emplacement actuel. Son seul cas d'utilisation si vous souhaitez enregistrer et relire des actions, et mettre à jour la barre d'adresse lorsque vous les relisez.

Il n’est nullement nécessaire - dans la plupart des cas, d’utiliser simplement React directement le routeur suffit.

51
Dan Abramov

En bref : Vous pouvez utiliser redux-query-sync pour conserver les paramètres d'URL et les champs du magasin synchronisés. Cela fonctionne sans routeur.


Histoire plus longue : Luttant avec la même question, j'ai d'abord apprécié le commentaire de Dan Abramov réponse , suggérant de (dans mes mots) considérer le URL en tant que "deuxième magasin", une partie de l'état de l'application en dehors du magasin Redux. Mais j’ai ensuite constaté qu’avoir deux types de "magasins" rend difficile la modification de code, par exemple. déplacez les objets de l'un à l'autre, car chaque "magasin" a une interface différente. En tant que développeur, j'aimerais plutôt sélectionner l'un des champs de mon état Redux et les exposer dans l'URL, comme si l'emplacement était un petite fenêtre sur (une partie de) mon état.

Je viens donc de publier redux-query-sync, pour vous permettre de fournir une fonction de sélecteur permettant de sélectionner une valeur à partir de l'état, qui est ensuite exposée à l'emplacement de la fenêtre sous un nom de paramètre que vous spécifiez. Pour qu’il soit également synchronisé dans l’autre sens, donc de l’URL à l’état Redux (par exemple, lors du chargement initial de l’application), vous pouvez fournir un créateur d’action à qui sera transmise la valeur du paramètre afin que votre réducteur puisse le mettre à jour en conséquence.

12
Gerben

Voici comment j'ai géré le premier scénario:

  • Lorsque la valeur d'entrée change, son composant déclenche un rappel qui a été transmis comme accessoire de son conteneur.

  • Dans le rappel, le conteneur distribue l'action responsable de la mise à jour de l'état Redux lorsque l'événement se produit.

  • Dans la ligne qui suit immédiatement l'appel à l'action, j'utilise this.context.router.Push() et lui passe l'URL avec la chaîne de requête correcte.

Je ne suis pas sûr que ce soit la bonne approche. Je l'ai trouvé préférable de mettre à jour l'URL car, à mon avis, la chaîne de requête devrait refléter l'état plutôt que le maître.

En ce qui concerne le scénario inverse, je ne suis vraiment pas sûr. Il semble que définir manuellement l'URL déclencherait un rechargement complet, mais je me trompe peut-être.

En ce qui concerne le routeur à utiliser, j'utilise React routeur en lui-même. Je ne trouvais pas vraiment utile d'utiliser les autres et cette discussion était décisif pour moi. .

2
cantera

J'ai récemment fini de travailler sur un problème similaire à celui-ci. J'ai utilisé MobX comme magasin et redux-router comme routeur. (J'ai bien réagi avec react-router, mais je devais envoyer une action Push en dehors du composant - redux en tant que magasin global fonctionne très bien ici)

Ma solution a été similaire à celle décrite par cantera: mon état de routeur est simplement un reflet de l'état de la forme. Cela a l'avantage supplémentaire de ne pas avoir à abandonner mon état de formulaire et de dépendre entièrement de l'état du routeur.


Dans le premier scénario,

1) Je mets à jour mon entrée de formulaire comme d’habitude, ce qui déclenche un re-rendu dans le composant de résultats.

2) Dans componentDidUpdate() du composant de résultats, j'utilise les accessoires de formulaire pour construire la chaîne de requête mise à jour.

3) I Poussez la chaîne de requête mise à jour vers l'état du routeur. Ceci est uniquement pour l'effet de la mise à jour de l'URL.


Pour le deuxième scénario

1) Dans le hook onEnter du composant racine Route, je récupère la chaîne de requête disponible et l’analyse dans les valeurs de formulaire initiales.

2) Je mets à jour mon magasin avec les valeurs. Ceci ne concerne que le premier chargement de la page, et la seule fois où l'état du routeur dicte l'état du formulaire.


Edit: Cette solution ne prend pas en compte le cas lorsque vous revenez dans l'historique de votre navigateur, car l'URL ne mettra pas à jour votre état.

2
xiankai

Je recommanderais le nouvel outil react-url-query , qui effectuera cette synchronisation assez rapidement.

1
Hearen