내가 제안하는 접근법은 약간 장황하지만 복잡한 앱으로 확장하는 것이 좋습니다. 모달을 표시 하려면보고자 하는 모달을 설명하는 동작 을 시작하십시오.
모달을 보여주기 위해 액션 전달
this.props.dispatch({
type: 'SHOW_MODAL',
modalType: 'DELETE_POST',
modalProps: {
postId: 42
}
})
(물론 문자열은 상수 일 수 있습니다. 단순화를 위해 인라인 문자열을 사용하고 있습니다.)
모달 상태를 관리하기위한 감속기 작성
그런 다음 다음 값만 허용하는 감속기가 있는지 확인하십시오.
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 */
})
큰! 이제 액션을 디스패치 state.modal하면 현재 보이는 모달 창에 대한 정보가 포함되도록 업데이트됩니다.
루트 모달 컴포넌트 작성
컴포넌트 계층 구조의 루트 <ModalRoot>에서 Redux 저장소에 연결된 컴포넌트를 추가하십시오 . state.modal적절한 모달 컴포넌트 를 듣고 표시하여의 소품을 전달합니다 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)
우리는 여기서 무엇을 했습니까? ModalRoot전류를 판독 modalType하고 modalProps에서 state.modal되는 것이 접속되고, 대응하는 요소와 같은 렌더링 DeletePostModal하거나 ConfirmLogoutModal. 모든 모달은 컴포넌트입니다!
특정 모달 구성 요소 작성
여기에는 일반적인 규칙이 없습니다. 그것들은 액션을 디스패치하고, 스토어 상태에서 무언가를 읽고, 모달이 될 수있는 React 컴포넌트 일뿐 입니다.
예를 들어 DeletePostModal다음과 같습니다.
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)
는 DeletePostModal이 연결된 모든 구성 요소와 같은 게시물 제목과 작품을 표시 할 수 있도록 저장소에 연결되어 : 그것은 포함하여, 작업을 전달할 수 있습니다 hideModal그 자체를 숨길 필요가있을 때.
프리젠 테이션 컴포넌트 추출
모든“특정”모달에 대해 동일한 레이아웃 논리를 복사하여 붙여 넣기하는 것은 어색합니다. 하지만 구성 요소가 있습니까? 따라서 특정 모달의 기능을 모르지만 모양을 처리하는 프레젠테이션 <Modal> 구성 요소를 추출 할 수 있습니다 .
그런 다음과 같은 특정 모달 DeletePostModal은 렌더링에 사용할 수 있습니다.
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)
<Modal>응용 프로그램에서 수락 할 수 있는 소품 세트를 생각해내는 것은 당신 에게 달려 있지만, 여러 종류의 모달 (예 : 정보 모달, 확인 모달 등) 및 여러 가지 스타일이있을 수 있다고 생각합니다.
접근성 및 외부 클릭 또는 이스케이프 키 숨기기
모달의 마지막 중요한 부분은 일반적으로 사용자가 외부를 클릭하거나 이스케이프를 누를 때 숨기려고한다는 것입니다.
이 구현에 대한 조언을 제공하는 대신 직접 구현하지 않는 것이 좋습니다. 접근성을 고려하여 올바르게 얻기가 어렵습니다.
대신, 와 같은 접근 가능한 상용 모달 구성 요소 를 사용하는 것이 좋습니다 react-modal. 그것은 완전히 사용자 정의가 가능하며, 원하는 것을 무엇이든 넣을 수 있지만 시각 장애인이 여전히 모달을 사용할 수 있도록 접근성을 올바르게 처리합니다.
응용 프로그램에 맞는 소품을 받아들이고 자식 버튼이나 다른 내용을 생성하는 react-modal자신 만의 랩핑도 가능 <Modal>합니다. 그것은 단지 구성 요소입니다!
다른 접근법
여러 가지 방법이 있습니다.
어떤 사람들은이 접근 방식의 장황함을 좋아하지 않으며 “포털”이라는 기술로 컴포넌트 내부에서<Modal> 렌더링 할 수 있는 컴포넌트를 선호합니다 . 포털을 사용하면 컴포넌트를 렌더링 할 수 있으며 실제로 는 DOM의 미리 결정된 위치에서 렌더링되므로 모달에 매우 편리합니다.
사실 react-modal이전에 이미 링크를 했으므로 기술적으로 내부적으로 그렇게 할 수 있으므로 맨 위에서 렌더링 할 필요조차 없습니다. 나는 여전히 그것을 보여주는 구성 요소에서 보여주고 싶은 모달을 분리하는 것이 좋지만, 당신은 또한 react-modal당신의 구성 요소에서 직접 사용할 수 있으며 위에서 쓴 것을 대부분 건너 뛸 수 있습니다 .
두 가지 접근 방식을 모두 고려하고 실험하고 앱과 팀에 가장 적합한 것을 선택하는 것이 좋습니다.