272 votes

Comment puis-je afficher une boîte de dialogue modale dans Redux qui effectue des actions asynchrones?

Je suis en train de construire une application qui a besoin d'afficher une boîte de dialogue de confirmation dans certaines situations.

Disons que je veux enlever quelque chose, alors je vais envoyer une action comme deleteSomething(id) de sorte que certains réducteur attraper cet événement et va remplir la boîte de dialogue réducteur pour le montrer.

Mon doute vient quand cette boîte de dialogue soumet.

  • Comment cette composante de l'expédition, l'action appropriée en fonction de la première action distribué?
  • Si l'action créateur de gérer cette logique?
  • Peut-on ajouter des actions à l'intérieur du réducteur?

edit:

pour le rendre plus clair:

deleteThingA(id) => show dialog with Questions => deleteThingARemotely(id)

createThingB(id) => Show dialog with Questions => createThingBRemotely(id)

Donc j'essaye de réutiliser la boîte de dialogue composants. Afficher/masquer la boîte de dialogue, il n'est pas le problème que cela peut être fait facilement dans le réducteur. Ce que j'essaie de préciser, c'est comment à l'envoi de l'action à partir de la droite en fonction de l'action qui démarre le flux dans le côté gauche.

556voto

Dan Points 16670

L'approche que je suggère, c'est un peu verbeux, mais je l'ai trouvé à l'échelle assez bien à des applications complexes. Lorsque vous souhaitez afficher un modal, le feu d'une action décrivant ce qui modale vous voulez voir:

En envoyant une Action pour Montrer la Modale

this.props.dispatch({
  type: 'SHOW_MODAL',
  modalType: 'DELETE_POST',
  modalProps: {
    postId: 42
  }
})

(Chaînes de caractères peuvent être des constantes, bien sûr; je suis à la volée des chaînes pour des raisons de simplicité.)

L'écriture d'un Réducteur pour Gérer l'État Modal

Ensuite, assurez-vous d'avoir un réducteur juste accepte ces valeurs:

const initialState = {
  modalType: null,
  modalProps: {}
}

function modal(state = initialState, action) {
  switch (action.type) {
    case 'SHOW_MODAL':
      return {
        modalType: action.modalType,
        modalProps: action.modalProps
      }
    case 'HIDE_MODAL':
      return initialState
    default:
      return state
  }
}

/* .... */

const rootReducer = combineReducers({
  modal,
  /* other reducers */
})

Super! Maintenant, lorsque vous envoi une action, state.modal sera mis à jour pour inclure les informations sur le actuellement visible fenêtre modale.

L'écriture de la Racine de la Composante Modale

À la racine de votre hiérarchie des composants, ajouter un <ModalRoot> composant qui est connecté à la Redux magasin. Il sera à l'écoute de state.modal et affichage approprié modal composant, de transférer les accessoires de l' state.modal.modalProps.

// These are regular React components we will write soon
import DeletePostModal from './DeletePostModal'
import ConfirmLogoutModal from './ConfirmLogoutModal'

const MODAL_COMPONENTS = {
  'DELETE_POST': DeletePostModal,
  'CONFIRM_LOGOUT': ConfirmLogoutModal,
  /* other modals */
}

const ModalRoot = ({ modalType, modalProps }) => {
  if (!modalType) {
    return <span /> // after React v15 you can return null here
  }

  const SpecificModal = MODAL_COMPONENTS[modalType]
  return <SpecificModal {...modalProps} />
}

export default connect(
  state => state.modal
)(ModalRoot)

Qu'avons-nous fait ici? ModalRoot indique le courant modalType et modalProps de state.modal auquel il est connecté, et rend un composant correspondant comme DeletePostModal ou ConfirmLogoutModal. Chaque modal est un composant!

L'Écriture Spécifique Modale Des Composants

Il n'existe pas de règles générales ici. Ils sont simplement Réagir face à des composants de l'expédition d'actions, de lire quelque chose à partir du magasin de l'etat, et juste arriver à être les auxiliaires modaux.

Par exemple, DeletePostModal pourrait ressembler à:

import { deletePost, hideModal } from '../actions'

const DeletePostModal = ({ post, dispatch }) => (
  <div>
    <p>Delete post {post.name}?</p>
    <button onClick={() => {
      dispatch(deletePost(post.id)).then(() => {
        dispatch(hideModal())
      })
    }}>
      Yes
    </button>
    <button onClick={() => dispatch(hideModal())}>
      Nope
    </button>
  </div>
)

export default connect(
  (state, ownProps) => ({
    post: state.postsById[ownProps.postId]
  })
)(DeletePostModal)

L' DeletePostModal est connecté à la boutique il possible d'afficher le titre du post et fonctionne comme n'importe quel composant connecté: il peut envoyer des actions, y compris l' hideModal lorsqu'il est nécessaire de se cacher.

L'extraction d'une Présentation de la Composante

Il serait maladroit de copier-coller la même logique de présentation pour chaque "spécifique" modal. Mais vous avez des composants, droit? De sorte que vous pouvez extraire une présentation <Modal> composant qui ne sait pas ce qu'particulier les auxiliaires modaux faire, mais les poignées de la façon dont ils regardent.

Ensuite, spécifiques des modaux tels que DeletePostModal pouvez l'utiliser pour le rendu:

import { deletePost, hideModal } from '../actions'
import Modal from './Modal'

const DeletePostModal = ({ post, dispatch }) => (
  <Modal
    dangerText={`Delete post ${post.name}?`}
    onDangerClick={() =>
      dispatch(deletePost(post.id)).then(() => {
        dispatch(hideModal())
      })
    })
  />
)

export default connect(
  (state, ownProps) => ({
    post: state.postsById[ownProps.postId]
  })
)(DeletePostModal)

C'est à vous de venir avec un ensemble d'accessoires qui <Modal> peut accepter dans votre application, mais j'imagine que vous pourriez avoir plusieurs types d'auxiliaires modaux (p. ex. info modal, la confirmation modal, etc), et plusieurs styles pour eux.

De l'accessibilité et de Cacher un Clic à l'Extérieur ou Échapper à la Clé

La dernière partie importante sur les auxiliaires modaux est que, généralement, nous voulons cacher lorsque l'utilisateur clique sur l'extérieur ou les presses à s'Échapper.

Au lieu de vous donner des conseils sur la mise en œuvre de la présente, je suggère que vous venez de ne pas mettre en œuvre vous-même. Il est difficile de faire droit compte tenu de l'accessibilité.

Au lieu de cela, je vous suggère d'utiliser un accessible hors-the-shelf modal composant tel qu' react-modal. Il est entièrement personnalisable, vous pouvez mettre ce que vous voulez à l'intérieur d'elle, mais elle gère l'accessibilité correctement de façon à ce que les personnes aveugles peuvent toujours utiliser votre modal.

Vous pouvez même terminer react-modal dans votre propre <Modal> qui accepte des accessoires spécifiques à vos applications et génère de l'enfant, de boutons ou d'autres contenus. C'est tout simplement les composants de!

D'Autres Approches

Il y a plus d'une façon de le faire.

Certaines personnes n'aiment pas le niveau de verbosité de cette approche et préfèrent avoir un <Modal> de la composante qu'ils peuvent se rendre directement à l'intérieur de leurs composants avec une technique appelée "portails". Portails vous permettent d'effectuer le rendu d'un composant à l'intérieur de la vôtre alors qu' en fait il va rendre à un endroit prédéterminé dans les DOM, ce qui est très pratique pour les auxiliaires modaux.

En fait, react-modal I lié à l'heure le fait déjà en interne donc, techniquement, vous n'avez même pas besoin de la calculer à partir du haut. Je trouve toujours agréable de découpler la modale je veux montrer à partir de la composante montrer, mais vous pouvez également utiliser react-modal directement à partir de vos composants, et passez la plupart de ce que j'ai écrit ci-dessus.

Je vous encourage à considérer les deux approches, de les expérimenter et de choisir ce que vous trouver qui fonctionne le mieux pour votre application et à votre équipe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X