Cách tiếp cận tôi đề xuất là hơi dài dòng nhưng tôi thấy nó có khả năng mở rộng khá tốt thành các ứng dụng phức tạp. Khi bạn muốn hiển thị một phương thức, bắn một hành động mô tả mà phương thức bạn muốn xem:
Gửi một hành động để hiển thị phương thức
this.props.dispatch({
type: 'SHOW_MODAL',
modalType: 'DELETE_POST',
modalProps: {
postId: 42
}
})
(Tất nhiên, chuỗi có thể là hằng số; Tôi đang sử dụng chuỗi nội tuyến để đơn giản.)
Viết một Reducer để quản lý trạng thái phương thức
Sau đó, đảm bảo bạn có một bộ giảm tốc chỉ chấp nhận các giá trị này:
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 */
})
Tuyệt quá! Bây giờ, khi bạn gửi một hành động, state.modal
sẽ cập nhật để bao gồm thông tin về cửa sổ phương thức hiện có thể nhìn thấy.
Viết thành phần gốc Modal
Tại thư mục gốc của cấu trúc phân cấp, hãy thêm một <ModalRoot>
thành phần được kết nối với cửa hàng Redux. Nó sẽ lắng nghestate.modal
và hiển thị một thành phần phương thức thích hợp, chuyển tiếp các đạo cụ từ 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)
Chúng ta đã làm gì ở đây? ModalRoot
đọc hiện tại modalType
vàmodalProps
từ state.modal
đó nó được kết nối và kết xuất một thành phần tương ứng như DeletePostModal
hoặc ConfirmLogoutModal
. Mỗi phương thức là một thành phần!
Viết các thành phần phương thức cụ thể
Không có quy tắc chung ở đây. Chúng chỉ là các thành phần React có thể gửi hành động, đọc thứ gì đó từ trạng thái cửa hàng, và tình cờ là phương thức .
Ví dụ: DeletePostModal
có thể trông như:
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)
Các DeletePostModal
được kết nối với cửa hàng để nó có thể hiển thị tiêu đề bài đăng và hoạt động giống như bất kỳ thành phần nào được kết nối: nó có thể gửi các hành động, kể cả hideModal
khi cần phải ẩn chính nó.
Trích xuất một thành phần trình bày
Sẽ rất khó khăn khi sao chép-dán cùng một logic bố cục cho mỗi phương thức cụ thể của Wap. Nhưng bạn có các thành phần, phải không? Vì vậy, bạn có thể trích xuất một trình bày <Modal>
thành phần mà không biết phương thức cụ thể nào, nhưng xử lý chúng trông như thế nào.
Sau đó, các phương thức cụ thể như DeletePostModal
có thể sử dụng nó để kết xuất:
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)
Tùy thuộc vào bạn để đưa ra một bộ đạo cụ <Modal>
có thể chấp nhận trong ứng dụng của bạn nhưng tôi sẽ tưởng tượng rằng bạn có thể có một số loại phương thức (ví dụ: phương thức thông tin, phương thức xác nhận, v.v.) và một số kiểu cho chúng.
Khả năng truy cập và ẩn trên Nhấp vào bên ngoài hoặc Phím thoát
Phần quan trọng cuối cùng về phương thức là nói chung chúng tôi muốn ẩn chúng khi người dùng nhấp vào bên ngoài hoặc nhấn Escape.
Thay vì cho bạn lời khuyên về việc thực hiện điều này, tôi khuyên bạn không nên tự mình thực hiện nó. Thật khó để có được quyền xem xét khả năng tiếp cận.
Thay vào đó, tôi sẽ đề nghị bạn sử dụng một thành phần phương thức có sẵn có thể truy cập như react-modal
. Nó hoàn toàn có thể tùy chỉnh, bạn có thể đặt bất cứ thứ gì bạn muốn vào bên trong nó, nhưng nó xử lý khả năng truy cập chính xác để người mù vẫn có thể sử dụng phương thức của bạn.
Bạn thậm chí có thể react-modal
tự mình <Modal>
chấp nhận các đạo cụ cụ thể cho các ứng dụng của mình và tạo các nút con hoặc nội dung khác. Tất cả chỉ là thành phần!
Phương pháp khác
Có nhiều hơn một cách để làm điều đó.
Một số người không thích sự dài dòng của phương pháp này và thích có một <Modal>
thành phần mà họ có thể kết xuất ngay bên trong các thành phần của mình bằng một kỹ thuật có tên là Cổng portals. Cổng cho phép bạn kết xuất một thành phần bên trong của bạn trong khi thực sự nó sẽ kết xuất tại một địa điểm được xác định trước trong DOM, rất thuận tiện cho các phương thức.
Trong thực tế, react-modal
tôi đã liên kết với trước đó đã làm điều đó trong nội bộ vì vậy về mặt kỹ thuật, bạn thậm chí không cần phải hiển thị nó từ đầu. Tôi vẫn thấy tốt khi tách rời phương thức tôi muốn hiển thị từ thành phần hiển thị nó, nhưng bạn cũng có thể sử dụng react-modal
trực tiếp từ các thành phần của mình và bỏ qua hầu hết những gì tôi đã viết ở trên.
Tôi khuyến khích bạn xem xét cả hai cách tiếp cận, thử nghiệm với chúng và chọn những gì bạn thấy phù hợp nhất với ứng dụng của bạn và cho nhóm của bạn.