내가 제안하는 접근법은 약간 장황하지만 복잡한 앱으로 확장하는 것이 좋습니다. 모달을 표시 하려면보고자 하는 모달을 설명하는 동작 을 시작하십시오.
모달을 보여주기 위해 액션 전달
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
당신의 구성 요소에서 직접 사용할 수 있으며 위에서 쓴 것을 대부분 건너 뛸 수 있습니다 .
두 가지 접근 방식을 모두 고려하고 실험하고 앱과 팀에 가장 적합한 것을 선택하는 것이 좋습니다.