특정 페이지에서 이동할 때 ReactJS 앱이 사용자에게 알리기를 원합니다. 특히 조치를 취하도록 상기시키는 팝업 메시지 :
“변경 사항이 저장되었지만 아직 게시되지 않았습니다. 지금 수행 하시겠습니까?”
이를 react-router전역 적으로 트리거해야합니까 , 아니면 반응 페이지 / 구성 요소 내에서 수행 할 수 있습니까?
나는 후자에서 아무것도 찾지 못했고 차라리 첫 번째를 피하고 싶습니다. 물론 표준이 아니라면 사용자가 이동할 수있는 다른 모든 페이지에 코드를 추가하지 않고도 이러한 작업을 수행하는 방법이 궁금합니다.
모든 통찰력을 환영합니다, 감사합니다!
답변
react-routerv4는를 사용하여 탐색을 차단하는 새로운 방법을 도입했습니다 Prompt. 차단하려는 구성 요소에 다음을 추가하십시오.
import { Prompt } from 'react-router'
const MyComponent = () => (
  <React.Fragment>
    <Prompt
      when={shouldBlockNavigation}
      message='You have unsaved changes, are you sure you want to leave?'
    />
    {/* Component JSX */}
  </React.Fragment>
)
이렇게하면 라우팅이 차단되지만 페이지 새로 고침이나 닫기는 차단되지 않습니다. 이를 차단하려면 다음을 추가해야합니다 (필요에 따라 적절한 React 수명 주기로 업데이트).
componentDidUpdate = () => {
  if (shouldBlockNavigation) {
    window.onbeforeunload = () => true
  } else {
    window.onbeforeunload = undefined
  }
}
onbeforeunload 는 브라우저에서 다양한 지원을 제공합니다.
답변
react-router v2.4.0이상에서 v4몇 가지 옵션이 있기 전에
 <Route
      path="/home"
      onEnter={ auth }
      onLeave={ showConfirm }
      component={ Home }
    >
전환이 발생하지 않도록하거나 나가기 후크를 사용하여 경로를 떠나기 전에 사용자에게 메시지를 표시 할 수 있습니다.
const Home = withRouter(
  React.createClass({
    componentDidMount() {
      this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave)
    },
    routerWillLeave(nextLocation) {
      // return false to prevent a transition w/o prompting the user,
      // or return a string to allow the user to decide:
      // return `null` or nothing to let other hooks to be executed
      //
      // NOTE: if you return true, other hooks will not be executed!
      if (!this.state.isSaved)
        return 'Your work is not saved! Are you sure you want to leave?'
    },
    // ...
  })
)
이 예제에서는에 withRouter도입 된 고차 구성 요소를 사용합니다.v2.4.0.
그러나 이러한 솔루션은 URL에서 경로를 수동으로 변경할 때 완벽하게 작동하지 않습니다.
의미에서
- 확인이 표시됩니다.
 - 페이지 포함이 다시로드되지 않음-확인
 - URL이 변경되지 않음-괜찮지 않음
 
들어 react-router v4프롬프트 또는 사용자 정의 역사를 사용하여 :
그러나에서는 from’react-router react-router v4의 도움으로 구현하기가 다소 쉽습니다.Prompt
문서에 따르면
신속한
페이지에서 이동하기 전에 사용자에게 메시지를 표시하는 데 사용됩니다. 애플리케이션이 사용자가 다른 곳으로 이동하지 못하도록하는 상태가되면 (예 : 양식이 반만 채워져 있음)
<Prompt>.import { Prompt } from 'react-router' <Prompt when={formIsHalfFilledOut} message="Are you sure you want to leave?" />메시지 : 문자열
사용자가 다른 곳으로 이동하려고 할 때 묻는 메시지입니다.
<Prompt message="Are you sure you want to leave?"/>메시지 : func
사용자가 탐색을 시도하는 다음 위치 및 작업과 함께 호출됩니다. 사용자에게 프롬프트를 표시하려면 문자열을 반환하고 전환을 허용하려면 true를 반환합니다.
<Prompt message={location => ( `Are you sure you want to go to ${location.pathname}?` )}/>언제 : bool
<Prompt>가드 뒤를 조건부로 렌더링하는 대신 항상 렌더링 할 수 있지만 그에 따라 통과when={true}하거나when={false}탐색을 방지하거나 허용 할 수 있습니다.
렌더링 방법에서 필요에 따라 문서에 언급 된대로이를 추가하기 만하면됩니다.
최신 정보:
페이지를 사용할 때 사용자 지정 작업을 수행하려면 사용자 지정 기록을 사용하고 다음과 같이 라우터를 구성 할 수 있습니다.
history.js
import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()
...
import { history } from 'path/to/history';
<Router history={history}>
  <App/>
</Router>
그런 다음 구성 요소에서 다음 history.block과 같이 사용할 수 있습니다.
import { history } from 'path/to/history';
class MyComponent extends React.Component {
   componentDidMount() {
      this.unblock = history.block(targetLocation => {
           // take your action here     
           return false;
      });
   }
   componentWillUnmount() {
      this.unblock();
   }
   render() {
      //component render here
   }
}
답변
대한 react-router2.4.0+
참고 : react-router새로운 기능을 모두 얻으려면 모든 코드를 최신 코드로 마이그레이션하는 것이 좋습니다 .
react-router 문서 에서 권장하는대로 :
withRouter고차 구성 요소를 사용해야합니다 .
우리는이 새로운 HoC가 더 좋고 더 쉬우 며 문서와 예제에서 사용할 것이라고 생각하지만 전환하는 것이 어려운 요구 사항은 아닙니다.
문서의 ES6 예 :
import React from 'react'
import { withRouter } from 'react-router'
const Page = React.createClass({
  componentDidMount() {
    this.props.router.setRouteLeaveHook(this.props.route, () => {
      if (this.state.unsaved)
        return 'You have unsaved information, are you sure you want to leave this page?'
    })
  }
  render() {
    return <div>Stuff</div>
  }
})
export default withRouter(Page)
답변
대한 react-routerV3.0의
페이지에 저장되지 않은 변경 사항에 대한 확인 메시지가 필요한 동일한 문제가 발생했습니다. 제 경우에는 React Router v3을 사용 하고 있었기 때문에 React Router v4<Prompt /> 에서 도입 한을 사용할 수 없었습니다 .
나는의 조합으로 ‘뒤로’버튼 클릭 ‘과’실수로 링크를 클릭 ‘으로 처리 setRouteLeaveHook하고 history.pushState(), 그리고 함께’새로 고침 버튼을 ‘처리하는 onbeforeunload이벤트 핸들러.
setRouteLeaveHook ( doc ) 및 history.pushState ( doc )
- 
setRouteLeaveHook 만 사용하는 것만으로는 충분하지 않았습니다. 왠지 ‘뒤로’버튼을 클릭했을 때 페이지는 그대로 유지 되었으나 URL이 변경되었습니다.
// setRouteLeaveHook returns the unregister method this.unregisterRouteHook = this.props.router.setRouteLeaveHook( this.props.route, this.routerWillLeave ); ... routerWillLeave = nextLocation => { // Using native 'confirm' method to show confirmation message const result = confirm('Unsaved work will be lost'); if (result) { // navigation confirmed return true; } else { // navigation canceled, pushing the previous path window.history.pushState(null, null, this.props.route.path); return false; } }; 
onbeforeunload ( 문서 )
- 
‘실수 재 장전’버튼 처리에 사용됩니다.
window.onbeforeunload = this.handleOnBeforeUnload; ... handleOnBeforeUnload = e => { const message = 'Are you sure?'; e.returnValue = message; return message; } 
아래는 내가 작성한 전체 구성 요소입니다.
- 참고 withRouter가 가지고하는 데 사용됩니다 
this.props.router. - 참고 
this.props.route호출 구성 요소에서 아래로 전달됩니다 - 
참고
currentState소품으로 전달되어 초기 상태가하고 변화를 확인하기 위해import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; import { withRouter } from 'react-router'; import Component from '../Component'; import styles from './PreventRouteChange.css'; class PreventRouteChange extends Component { constructor(props) { super(props); this.state = { // initialize the initial state to check any change initialState: _.cloneDeep(props.currentState), hookMounted: false }; } componentDidUpdate() { // I used the library called 'lodash' // but you can use your own way to check any unsaved changed const unsaved = !_.isEqual( this.state.initialState, this.props.currentState ); if (!unsaved && this.state.hookMounted) { // unregister hooks this.setState({ hookMounted: false }); this.unregisterRouteHook(); window.onbeforeunload = null; } else if (unsaved && !this.state.hookMounted) { // register hooks this.setState({ hookMounted: true }); this.unregisterRouteHook = this.props.router.setRouteLeaveHook( this.props.route, this.routerWillLeave ); window.onbeforeunload = this.handleOnBeforeUnload; } } componentWillUnmount() { // unregister onbeforeunload event handler window.onbeforeunload = null; } handleOnBeforeUnload = e => { const message = 'Are you sure?'; e.returnValue = message; return message; }; routerWillLeave = nextLocation => { const result = confirm('Unsaved work will be lost'); if (result) { return true; } else { window.history.pushState(null, null, this.props.route.path); if (this.formStartEle) { this.moveTo.move(this.formStartEle); } return false; } }; render() { return ( <div> {this.props.children} </div> ); } } PreventRouteChange.propTypes = propTypes; export default withRouter(PreventRouteChange); 
질문이 있으면 알려주세요 🙂
답변
들어 react-router와 v0.13.x reactv0.13.x :
이는 willTransitionTo()및 willTransitionFrom()정적 메서드를 사용하여 가능 합니다. 최신 버전은 아래의 다른 답변을 참조하십시오.
로부터 반응-라우터 설명서 :
경로 전환 중에 호출 될 경로 처리기에서 일부 정적 메서드를 정의 할 수 있습니다.
willTransitionTo(transition, params, query, callback)핸들러가 렌더링 되려고 할 때 호출되어 전환을 중단하거나 리디렉션 할 수 있습니다. 비동기 작업을 수행하는 동안 전환을 일시 중지하고 완료되면 callback (error)을 호출하거나 인수 목록에서 콜백을 생략하면 호출됩니다.
willTransitionFrom(transition, component, callback)활성 경로가 전환 될 때 호출되어 전환을 중단 할 수 있습니다. 구성 요소는 현재 구성 요소이므로 전환을 허용할지 여부를 결정하기 위해 상태를 확인하는 데 필요할 수 있습니다 (양식 필드 등).
예
var Settings = React.createClass({ statics: { willTransitionTo: function (transition, params, query, callback) { auth.isLoggedIn((isLoggedIn) => { transition.abort(); callback(); }); }, willTransitionFrom: function (transition, component) { if (component.formHasUnsavedData()) { if (!confirm('You have unsaved information,'+ 'are you sure you want to leave this page?')) { transition.abort(); } } } } //... });
들어 react-router1.0.0-RC1 react이후 v0.14.x 또는 :
이것은 routerWillLeave라이프 사이클 후크 로 가능해야합니다 . 이전 버전의 경우 위의 내 대답을 참조하십시오.
로부터 반응-라우터 설명서 :
이 후크를 설치하려면 경로 구성 요소 중 하나에서 수명주기 믹스 인을 사용합니다.
import { Lifecycle } from 'react-router' const Home = React.createClass({ // Assuming Home is a route component, it may use the // Lifecycle mixin to get a routerWillLeave method. mixins: [ Lifecycle ], routerWillLeave(nextLocation) { if (!this.state.isSaved) return 'Your work is not saved! Are you sure you want to leave?' }, // ... })
소지품. 최종 출시 전에 변경 될 수 있습니다.
답변
이 프롬프트를 사용할 수 있습니다.
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link, Prompt } from "react-router-dom";
function PreventingTransitionsExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Form</Link>
          </li>
          <li>
            <Link to="/one">One</Link>
          </li>
          <li>
            <Link to="/two">Two</Link>
          </li>
        </ul>
        <Route path="/" exact component={Form} />
        <Route path="/one" render={() => <h3>One</h3>} />
        <Route path="/two" render={() => <h3>Two</h3>} />
      </div>
    </Router>
  );
}
class Form extends Component {
  state = { isBlocking: false };
  render() {
    let { isBlocking } = this.state;
    return (
      <form
        onSubmit={event => {
          event.preventDefault();
          event.target.reset();
          this.setState({
            isBlocking: false
          });
        }}
      >
        <Prompt
          when={isBlocking}
          message={location =>
            `Are you sure you want to go to ${location.pathname}`
          }
        />
        <p>
          Blocking?{" "}
          {isBlocking ? "Yes, click a link or the back button" : "Nope"}
        </p>
        <p>
          <input
            size="50"
            placeholder="type something to block transitions"
            onChange={event => {
              this.setState({
                isBlocking: event.target.value.length > 0
              });
            }}
          />
        </p>
        <p>
          <button>Submit to stop blocking</button>
        </p>
      </form>
    );
  }
}
export default PreventingTransitionsExample;
답변
history.listen 사용
예를 들면 아래와 같습니다.
구성 요소에서
componentWillMount() {
    this.props.history.listen(() => {
      // Detecting, user has changed URL
      console.info(this.props.history.location.pathname);
    });
}
