Programing

리액터 라우터 경로 전환과 함께 사용자 지정 구성 요소를 사용하는 방법

c10106 2022. 3. 28. 20:55
반응형

리액터 라우터 경로 전환과 함께 사용자 지정 구성 요소를 사용하는 방법

탐색 확인 기사는 전환 후크에서 브라우저 확인 상자를 사용하는 방법을 설명한다.좋아. 하지만 나만의 대화 상자를 사용하고 싶어.만약 내가 그 방법들을 사용한다면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>
    )
  }
}

참조URL: https://stackoverflow.com/questions/35275344/how-to-use-a-custom-component-with-react-router-route-transitions

반응형