Der Ansatz, den ich vorschlage, ist etwas ausführlich, aber ich fand, dass er sich ziemlich gut in komplexe Apps skalieren lässt. Wenn Sie ein Modal anzeigen möchten, lösen Sie eine Aktion aus, die beschreibt, welches Modal Sie sehen möchten :
Auslösen einer Aktion zum Anzeigen des Modals
this.props.dispatch({
type: 'SHOW_MODAL',
modalType: 'DELETE_POST',
modalProps: {
postId: 42
}
})
(Strings können natürlich Konstanten sein; ich verwende der Einfachheit halber Inline-Strings.)
Schreiben eines Reduzierers zum Verwalten des Modalstatus
Stellen Sie dann sicher, dass Sie einen Reduzierer haben, der nur diese Werte akzeptiert:
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 */
})
Toll! Wenn Sie jetzt eine Aktion auslösen, state.modal
wird diese aktualisiert und enthält nun Informationen zum aktuell sichtbaren modalen Fenster.
Schreiben der Root-Modalkomponente
Fügen Sie im Stammverzeichnis Ihrer Komponentenhierarchie eine <ModalRoot>
Komponente hinzu, die mit dem Redux-Speicher verbunden ist. Es wird zuhörenstate.modal
eine geeignete modale Komponente und anzeigen und die Requisiten von der weiterleiten 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)
Was haben wir hier gemacht? ModalRoot
liest den aktuellen modalType
undmodalProps
von state.modal
dem aus er verbunden ist, und rendert eine entsprechende Komponente wie DeletePostModal
oder ConfirmLogoutModal
. Jedes Modal ist eine Komponente!
Schreiben spezifischer modaler Komponenten
Hier gibt es keine allgemeinen Regeln. Sie sind nur React-Komponenten, die Aktionen auslösen, etwas aus dem Speicherstatus lesen können, auslösen und zufällig Modalitäten sein können .
Zum Beispiel DeletePostModal
könnte es so aussehen:
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)
Das DeletePostModal
ist mit dem Geschäft verbunden, sodass es den Post-Titel anzeigen kann und wie jede verbundene Komponente funktioniert: Es kann Aktionen auslösen, auch hideModal
wenn es notwendig ist, sich selbst zu verstecken.
Extrahieren einer Präsentationskomponente
Es wäre umständlich, für jedes „spezifische“ Modal dieselbe Layoutlogik zu kopieren und einzufügen. Aber Sie haben Komponenten, richtig? So können Sie eine Präsentation extrahieren <Modal>
, die nicht weiß, was bestimmte Modalitäten tun, aber wie sie aussehen.
Dann können bestimmte Modalitäten, wie DeletePostModal
sie zum Rendern verwendet werden können:
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)
Es liegt an Ihnen, eine Reihe von Requisiten zu entwickeln, <Modal>
die in Ihrer Anwendung akzeptiert werden können, aber ich würde mir vorstellen, dass Sie verschiedene Arten von Modalitäten (z. B. Info-Modal, Bestätigungsmodal usw.) und verschiedene Stile für diese haben.
Zugänglichkeit und Ausblenden bei Klicken außerhalb oder Escape-Taste
Der letzte wichtige Teil bei Modals ist, dass wir sie im Allgemeinen ausblenden möchten, wenn der Benutzer nach draußen klickt oder Escape drückt.
Anstatt Ihnen Ratschläge zur Implementierung zu geben, schlage ich vor, dass Sie es einfach nicht selbst implementieren. In Anbetracht der Zugänglichkeit ist es schwierig, das Richtige zu finden.
Stattdessen würde ich Ihnen empfehlen, eine zugängliche modale Standardkomponente wie z react-modal
. Es ist vollständig anpassbar, Sie können alles hineinstecken, was Sie wollen, aber es handhabt die Zugänglichkeit korrekt, so dass Blinde Ihr Modal weiterhin verwenden können.
Sie können sogar react-modal
Ihre eigenen <Modal>
einbinden, die für Ihre Anwendungen spezifische Requisiten akzeptieren und untergeordnete Schaltflächen oder andere Inhalte generieren. Es sind alles nur Komponenten!
Andere Ansätze
Es gibt mehr als einen Weg, dies zu tun.
Einige Leute mögen die Ausführlichkeit dieses Ansatzes nicht und bevorzugen eine <Modal>
Komponente, die sie mit einer Technik namens „Portale“ direkt in ihren Komponenten rendern können . Mit Portalen können Sie eine Komponente in Ihrem rendern, während sie tatsächlich an einer vorbestimmten Stelle im DOM gerendert wird, was für Modale sehr praktisch ist.
Tatsächlich habe react-modal
ich das schon früher intern gemacht, so dass Sie es technisch nicht einmal von oben rendern müssen. Ich finde es immer noch schön, das Modal, das ich zeigen möchte, von der Komponente zu entkoppeln, die es zeigt, aber Sie können es auch react-modal
direkt von Ihren Komponenten verwenden und das meiste, was ich oben geschrieben habe, überspringen.
Ich ermutige Sie, beide Ansätze zu berücksichtigen, mit ihnen zu experimentieren und auszuwählen, was für Ihre App und Ihr Team am besten geeignet ist.