리액터 라우터 경로 전환과 함께 사용자 지정 구성 요소를 사용하는 방법
탐색 확인 기사는 전환 후크에서 브라우저 확인 상자를 사용하는 방법을 설명한다.좋아. 하지만 나만의 대화 상자를 사용하고 싶어.만약 내가 그 방법들을 사용한다면history
나는 이것이 가능하다고 생각한다.이렇게 할 수 있을까?setRouteLeaveHook
리액트레이닝으로?
핵심 문제는 이다.setRouteLeaveHook
후크 기능이 동기적으로 결과를 반환할 것으로 예상한다.즉, 사용자 정의 대화 상자 구성 요소를 표시할 시간이 없으며 사용자가 옵션을 클릭할 때까지 기다렸다가 결과를 반환하십시오.그래서 비동기식 후크를 지정할 방법이 필요하다.여기 내가 쓴 유틸리티 기능이 있다.
// Asynchronous version of `setRouteLeaveHook`.
// Instead of synchronously returning a result, the hook is expected to
// return a promise.
function setAsyncRouteLeaveHook(router, route, hook) {
let withinHook = false
let finalResult = undefined
let finalResultSet = false
router.setRouteLeaveHook(route, nextLocation => {
withinHook = true
if (!finalResultSet) {
hook(nextLocation).then(result => {
finalResult = result
finalResultSet = true
if (!withinHook && nextLocation) {
// Re-schedule the navigation
router.push(nextLocation)
}
})
}
let result = finalResultSet ? finalResult : false
withinHook = false
finalResult = undefined
finalResultSet = false
return result
})
}
VEX를 사용하여 대화 상자를 표시하는 방법의 예는 다음과 같다.
componentWillMount() {
setAsyncRouteLeaveHook(this.context.router, this.props.route, this.routerWillLeave)
}
routerWillLeave(nextLocation) {
return new Promise((resolve, reject) => {
if (!this.state.textValue) {
// No unsaved changes -- leave
resolve(true)
} else {
// Unsaved changes -- ask for confirmation
vex.dialog.confirm({
message: 'There are unsaved changes. Leave anyway?' + nextLocation,
callback: result => resolve(result)
})
}
})
}
당신이 항해를 확인했는지 여부에 대해 부울(boolean)을 설정하여 작동시켰다(react-router 2.8.x 사용).당신이 게시한 링크에 표시된 대로: https://github.com/ReactTraining/react-router/blob/master/docs/guides/ConfirmingNavigation.md
사용자에게 메시지를 표시하지 않는 전환을 방지하기 위해 false를 반환함
그러나, 그들은 후크도 등록되지 않은 것으로 해야 한다는 것을 언급하는 것을 잊어버렸다. 여기와 여기를 보라.
이를 통해 다음과 같은 자체 솔루션을 구현할 수 있다.
class YourComponent extends Component {
constructor() {
super();
const {route} = this.props;
const {router} = this.context;
this.onCancel = this.onCancel.bind(this);
this.onConfirm = this.onConfirm.bind(this);
this.unregisterLeaveHook = router.setRouteLeaveHook(
route,
this.routerWillLeave.bind(this)
);
}
componentWillUnmount() {
this.unregisterLeaveHook();
}
routerWillLeave() {
const {hasConfirmed} = this.state;
if (!hasConfirmed) {
this.setState({showConfirmModal: true});
// Cancel route change
return false;
}
// User has confirmed. Navigate away
return true;
}
onCancel() {
this.setState({showConfirmModal: false});
}
onConfirm() {
this.setState({hasConfirmed: true, showConfirmModal: true}, function () {
this.context.router.goBack();
}.bind(this));
}
render() {
const {showConfirmModal} = this.state;
return (
<ConfirmModal
isOpen={showConfirmModal}
onCancel={this.onCancel}
onConfirm={this.onConfirm} />
);
}
}
YourComponent.contextTypes = {
router: routerShape
};
인터셉트 백 버튼이나 경로 변경에 대한 솔루션을 게시하는 중.이것은 반응로터 2.8 이상과 함께 작동한다.로터랑도 마찬가지야
import React, {PropTypes as T} from 'react';
...
componentWillMount() {
this.context.router.setRouteLeaveHook(this.props.route, this.routerWillLeaveCallback.bind(this));
}
routerWillLeaveCallback(nextLocation) {
let showModal = this.state.unsavedChanges;
if (showModal) {
this.setState({
openUnsavedDialog: true,
unsavedResolveCallback: Promise.resolve
});
return false;
}
return true;
}
}
YourComponent.contextTypes = {
router: T.object.isRequired
};
위는 사용자가 과거로 돌아갈 때를 제외하고는 대단하다.다음과 같은 것이 문제를 해결해 주어야 한다.
if (!withinHook && nextLocation) {
if (nextLocation.action=='POP') {
router.goBack()
} else {
router.push(nextLocation)
}
}
여기 같은 것에 대한 나의 해결책이 있다.앱에 있는 모든 구성 요소를 포장하는 데 사용할 수 있는 사용자 지정 대화 상자 구성 요소를 만들었어.머리글을 싸서 모든 페이지에 표시할 수 있다.Redex Form을 사용한다고 가정하지만 간단히 교체할 수 있다.areThereUnsavedChanges
다른 양식 변경 확인 코드와 함께.또한 React Bootstrap 모달(반응 부트스트랩)을 사용하며, 사용자 지정 대화 상자로 다시 바꿀 수 있다.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { withRouter, browserHistory } from 'react-router'
import { translate } from 'react-i18next'
import { Button, Modal, Row, Col } from 'react-bootstrap'
// have to use this global var, because setState does things at unpredictable times and dialog gets presented twice
let navConfirmed = false
@withRouter
@connect(
state => ({ form: state.form })
)
export default class UnsavedFormModal extends Component {
constructor(props) {
super(props)
this.areThereUnsavedChanges = this.areThereUnsavedChanges.bind(this)
this.state = ({ unsavedFormDialog: false })
}
areThereUnsavedChanges() {
return this.props.form && Object.values(this.props.form).length > 0 &&
Object.values(this.props.form)
.findIndex(frm => (Object.values(frm)
.findIndex(field => field && field.initial && field.initial !== field.value) !== -1)) !== -1
}
render() {
const moveForward = () => {
this.setState({ unsavedFormDialog: false })
navConfirmed = true
browserHistory.push(this.state.nextLocation.pathname)
}
const onHide = () => this.setState({ unsavedFormDialog: false })
if (this.areThereUnsavedChanges() && this.props.router && this.props.routes && this.props.routes.length > 0) {
this.props.router.setRouteLeaveHook(this.props.routes[this.props.routes.length - 1], (nextLocation) => {
if (navConfirmed || !this.areThereUnsavedChanges()) {
navConfirmed = false
return true
} else {
this.setState({ unsavedFormDialog: true, nextLocation: nextLocation })
return false
}
})
}
return (
<div>
{this.props.children}
<Modal show={this.state.unsavedFormDialog} onHide={onHide} bsSize="sm" aria-labelledby="contained-modal-title-md">
<Modal.Header>
<Modal.Title id="contained-modal-title-md">WARNING: unsaved changes</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to leave the page without saving changes to the form?
<Row>
<Col xs={6}><Button block onClick={onHide}>Cancel</Button></Col>
<Col xs={6}><Button block onClick={moveForward}>OK</Button></Col>
</Row>
</Modal.Body>
</Modal>
</div>
)
}
}
'Programing' 카테고리의 다른 글
__pycache__란 무엇인가? (0) | 2022.03.28 |
---|---|
각도 2에서 RXJS를 사용하여 사용자 지정 이벤트를 관찰하는 방법 (0) | 2022.03.28 |
파이선 2.7 지원 종료? (0) | 2022.03.28 |
가상 환경 제거/삭제 방법 (0) | 2022.03.28 |
구성 요소에서 "vuetify" 전환을 사용하는 방법 (0) | 2022.03.28 |