Pendekatan yang saya sarankan agak bertele-tele, tetapi saya menemukan skala untuk aplikasi yang kompleks. Saat Anda ingin menunjukkan modal, jalankan tindakan yang menggambarkan modal mana yang ingin Anda lihat:
Mengirimkan Tindakan untuk Menampilkan Modal
this.props.dispatch({
type: 'SHOW_MODAL',
modalType: 'DELETE_POST',
modalProps: {
postId: 42
}
})
(String bisa menjadi konstanta tentu saja; Saya menggunakan string sebaris untuk kesederhanaan.)
Menulis Reducer untuk Mengelola Modal State
Kemudian pastikan Anda memiliki peredam yang hanya menerima nilai-nilai ini:
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 */
})
Bagus! Sekarang, ketika Anda mengirim tindakan, state.modal
akan diperbarui untuk memasukkan informasi tentang jendela modal yang saat ini terlihat.
Menulis Komponen Modal Root
Pada akar hierarki komponen Anda, tambahkan <ModalRoot>
komponen yang terhubung ke toko Redux. Ini akan mendengarkan state.modal
dan menampilkan komponen modal yang sesuai, meneruskan alat peraga dari 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)
Apa yang sudah kita lakukan di sini? ModalRoot
membaca arus modalType
dan modalProps
dari state.modal
mana itu terhubung, dan membuat komponen yang sesuai seperti DeletePostModal
atau ConfirmLogoutModal
. Setiap modal adalah komponen!
Menulis Komponen Modal Tertentu
Tidak ada aturan umum di sini. Mereka hanya komponen Bereaksi yang dapat mengirim tindakan, membaca sesuatu dari keadaan toko, dan kebetulan menjadi modals .
Misalnya, DeletePostModal
mungkin terlihat seperti:
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)
The DeletePostModal
terhubung ke toko sehingga dapat menampilkan judul posting dan karya-karya seperti komponen yang terhubung: dapat mengirimkan tindakan, termasuk hideModal
jika diperlukan untuk menyembunyikan diri.
Mengekstraksi Komponen Presentasi
Akan aneh untuk menyalin-menempel logika tata letak yang sama untuk setiap modal "spesifik". Tetapi Anda memiliki komponen, bukan? Jadi, Anda dapat mengekstraksi komponen presentasi <Modal>
yang tidak tahu apa yang dilakukan modals tertentu, tetapi menangani tampilannya.
Kemudian, modals spesifik seperti DeletePostModal
dapat menggunakannya untuk rendering:
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)
Terserah kepada Anda untuk datang dengan seperangkat alat peraga yang <Modal>
dapat menerima dalam aplikasi Anda, tetapi saya akan membayangkan bahwa Anda mungkin memiliki beberapa jenis modals (misalnya modal info, modal konfirmasi, dll), dan beberapa gaya untuk mereka.
Aksesibilitas dan Menyembunyikan di Klik Luar atau Tombol Escape
Bagian penting terakhir tentang modals adalah bahwa umumnya kita ingin menyembunyikannya ketika pengguna mengklik di luar atau menekan Escape.
Alih-alih memberi Anda saran untuk menerapkan ini, saya sarankan Anda tidak menerapkannya sendiri. Sulit untuk mendapatkan yang benar mengingat aksesibilitas.
Sebagai gantinya, saya akan menyarankan Anda untuk menggunakan komponen modal off-the-shelf yang dapat diakses seperti react-modal
. Ini benar-benar dapat dikustomisasi, Anda dapat memasukkan apa pun yang Anda inginkan di dalamnya, tetapi menangani aksesibilitas dengan benar sehingga orang buta masih dapat menggunakan modal Anda.
Anda bahkan dapat membungkus react-modal
sendiri <Modal>
yang menerima alat peraga khusus untuk aplikasi Anda dan menghasilkan tombol anak atau konten lainnya. Itu semua hanya komponen!
Pendekatan Lain
Ada lebih dari satu cara untuk melakukannya.
Beberapa orang tidak suka verbositas dari pendekatan ini dan lebih suka memiliki <Modal>
komponen yang dapat mereka render tepat di dalam komponen mereka dengan teknik yang disebut "portal". Portal memungkinkan Anda membuat komponen di dalam Anda sementara sebenarnya itu akan membuat di tempat yang telah ditentukan di DOM, yang sangat nyaman untuk modals.
Sebenarnya react-modal
saya ditautkan sebelumnya sudah melakukan itu secara internal sehingga secara teknis Anda bahkan tidak perlu membuatnya dari atas. Saya masih merasa senang untuk memisahkan modal yang ingin saya tunjukkan dari komponen yang menunjukkannya, tetapi Anda juga dapat menggunakan react-modal
langsung dari komponen Anda, dan melewatkan sebagian besar dari apa yang saya tulis di atas.
Saya mendorong Anda untuk mempertimbangkan kedua pendekatan, bereksperimen dengan mereka, dan memilih apa yang menurut Anda paling cocok untuk aplikasi Anda dan untuk tim Anda.