리액트 라우터를 사용하여 사용자가 페이지를 떠나는 것을 감지하는 중
내 ReactJS 앱이 특정 페이지에서 벗어날 때 사용자에게 알렸으면 합니다.특히 작업을 수행하도록 알려주는 팝업 메시지:
변경 내용은 저장되지만 아직 공개되지 않았습니다.지금 당장 할까?
를 거거 this this에서 요?react-router
또는 리액트 페이지/컴포넌트 내에서 실행할 수 있습니까?
후자에 대해선 아무것도 못 찾았고, 첫 번째는 피하고 싶어요물론 그것이 일반적인 것이 아니라면, 어떻게 하면 사용자가 갈 수 있는 다른 모든 페이지에 코드를 추가하지 않고 이런 일을 할 수 있을지 궁금하게 된다.
어떤 통찰이라도 환영합니다, 감사합니다!
react-router
는 v4를 사용하여 했습니다.Prompt
차단할 컴포넌트에 다음 내용을 추가합니다.
import { Prompt } from 'react-router'
const MyComponent = () => (
<>
<Prompt
when={shouldBlockNavigation}
message='You have unsaved changes, are you sure you want to leave?'
/>
{/* Component JSX */}
</>
)
그러면 라우팅이 차단되지만 페이지 새로 고침이나 닫힘은 차단되지 않습니다.이를 차단하려면 다음을 추가해야 합니다(필요에 따라 적절한 React 라이프 사이클로 업데이트).
componentDidUpdate = () => {
if (shouldBlockNavigation) {
window.onbeforeunload = () => true
} else {
window.onbeforeunload = undefined
}
}
onbeforeunload는 브라우저별로 다양한 지원을 제공합니다.
라우터의 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의 루트를 수동으로 변경할 때는 이러한 솔루션이 완벽하게 동작하지 않습니다.
그런 의미에서
- Confirmation - OK가 표시됩니다.
- 페이지 포함이 새로고침되지 않음 - OK
- URL이 변경되지 않음 - 괜찮지 않음
★★★의 react-router v4
"CHANGE: "CHANGE: "CHANGE: " 。
, ,에서는react-router v4
from'to-interminal의 도움을 받아 구현이 비교적 용이합니다.
서류에 의하면
신속한
페이지에서 이동하기 전에 사용자에게 묻기 위해 사용됩니다. 할 수 있는 처럼), 「」를 .
<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.disclosing
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-router
2.4.0+
메모: 모든 코드를 최신 버전으로 이행하여 모든 새로운 제품을 입수하는 것이 좋습니다.
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-router
1993.x.
페이지에 저장되지 않은 변경에 대한 확인 메시지가 필요한 것과 같은 문제가 있었습니다.제 경우 리액트 라우터 v3를 사용하고 있었기 때문에<Prompt />
는 React Router v4에서 도입되었습니다.
' 클릭과 ' 클릭'을 '뒤로 버튼 클릭'과 '우발 링크 클릭했습니다.setRouteLeaveHook
★★★★★★★★★★★★★★★★★」history.pushState()
'은 '버튼'을 '버튼'으로 처리했습니다.onbeforeunload
이벤트 핸들러
setRouteLeaveHook(doc) 및 history.pushState(doc)
set Route Leave Hook만 사용하는 것만으로는 충분하지 않았습니다.'뒤로 버튼'을 클릭했을 때 페이지는 그대로였지만, 어떤 이유로 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; } };
언로드 전(doc)
'우발적인 새로고침' 버튼을 처리하는 데 사용됩니다.
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);
질문이 있으시면 연락주세요.
이렇게 하면 사용자가 다른 경로로 전환하거나 현재 페이지를 떠나 다른 URL로 이동할 때 메시지를 표시할 수 있습니다.
import PropTypes from 'prop-types'
import React, { useEffect } from 'react'
import { Prompt } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
const LeavePageBlocker = ({ when }) => {
const { t } = useTranslation()
const message = t('page_has_unsaved_changes')
useEffect(() => {
if (!when) return () => {}
const beforeUnloadCallback = (event) => {
event.preventDefault()
event.returnValue = message
return message
}
window.addEventListener('beforeunload', beforeUnloadCallback)
return () => {
window.removeEventListener('beforeunload', beforeUnloadCallback)
}
}, [when, message])
return <Prompt when={when} message={message} />
}
LeavePageBlocker.propTypes = {
when: PropTypes.bool.isRequired,
}
export default LeavePageBlocker
페이지:
const [dirty, setDirty] = setState(false)
...
return (
<>
<LeavePageBlocker when={dirty} />
...
</>
)
history.listen 사용
예를 들어 다음과 같습니다.
컴포넌트에서는
componentWillMount() {
this.props.history.listen(() => {
// Detecting, user has changed URL
console.info(this.props.history.location.pathname);
});
}
★★★의 react-router
와 v0.13.x ®react
v0.13.x:
은 「 」를 사용하면 가능합니다.willTransitionTo()
★★★★★★★★★★★★★★★★★」willTransitionFrom()
는 다음 해 주세요.새로운 버전의 경우는, 다음의 답변을 참조해 주세요.
react-router 매뉴얼에서 다음 항목을 참조하십시오.
루트 전환 중에 호출되는 몇 가지 스태틱메서드를 루트핸들러로 정의할 수 있습니다.
willTransitionTo(transition, params, query, callback)
핸들러가 렌더하려고 하면 호출되며, 전환을 중단하거나 리디렉션할 수 있습니다.비동기 작업 중 이행을 일시 정지하거나 콜백(오류)을 완료하면 콜백을 인수 목록에서 생략하면 콜백이 호출됩니다.
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-router
1.0.0-rc1과react
v0.14.x 이후:
이것은, 다음의 방법으로 실현될 수 있습니다.routerWillLeave
라이프 사이클 훅이전 버전의 경우 위의 답변을 참조하십시오.
react-router 매뉴얼에서 다음 항목을 참조하십시오.
이 후크를 설치하려면 루트 컴포넌트 중 하나에 라이프 사이클 믹스인을 사용합니다.
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;
import React, {useEffect} from 'react';
import { useLocation} from 'react-router';
const prevLocation = useLocation().pathname;
useEffect(() => {
const unlisten = history.listen((location) => {
if (unsavedCondition && location.pathname !== prevLocation) {
history.push(prevLocation)
//Do something, like display confirmation dialog!
}
});
return () => {
unlisten()
}
},[])
사용할 수 있습니다.componentWillUnmount()
사용자가 페이지를 떠나기 전에 어떤 작업도 수행합니다.기능 컴포넌트를 사용하고 있는 경우는, 다음과 같이 할 수 있습니다.useEffect()
훅. 훅은 훅을 반환하는 함수를 받아들입니다.Destructor
이것은, 다음과 같습니다.componentWillUnmount()
할 수 있어요.
이 물건은 신용이 있다
react-router v3.x 및 기능 컴포넌트의 경우 다음과 같은 후크를 사용할 수 있습니다.
import { useEffect, useState } from "react";
import { usePrevious } from "./usePrevious";
const useConfirmation = ({ router, route, items }) => {
const [needConfirmation, setNeedConfirmation] = useState(false);
// You can use for the prevState any value, in my case it was length of items
const prevItemsLength = usePrevious({ length: items?.length });
const commonMsg =
"you-have-unsaved-information-are-you-sure-you-want-to-leave-this-page";
const onBeforeUnload = (e) => {
if (needConfirmation) {
e.returnValue = true;
return commonMsg;
}
return null;
};
const routerWillLeave = () => {
if (needConfirmation) {
return commonMsg;
}
return true;
};
useEffect(() => {
if (prevItemsLength?.length > items?.length) {
setNeedConfirmation(() => true);
}
}, [items]);
useEffect(() => {
if (needConfirmation) {
window.addEventListener("beforeunload", onBeforeUnload);
router.setRouteLeaveHook(route, routerWillLeave);
} else {
router.setRouteLeaveHook(route, () => {});
window.removeEventListener("beforeunload", onBeforeUnload);
}
return () => window.removeEventListener("beforeunload", onBeforeUnload);
}, [needConfirmation]);
return [needConfirmation, setNeedConfirmation];
};
export { useConfirmation };
그런 다음 다른 파일에서는 데이터가 저장된 후 확인을 비활성화합니다.
const [needConfirm, setNeedConfirm] = useConfirmation({
router,
route,
items,
});
const saveChanges = useCallback(() => {
//before turning off confirmation, there may be a request to the API to save our data
//if request was success then we set the 'needConfirm' value to 'false'
setNeedConfirm(() => false);
});
usePrevious' 후크에 대한 정보는 다음과 같습니다.반응 후크의 oldValues와 newValues를 비교하는 방법 useEffect?
언급URL : https://stackoverflow.com/questions/32841757/detecting-user-leaving-page-with-react-router
'it-source' 카테고리의 다른 글
스프링 부트 정보웹 환경을 올바르게 비활성화하는 방법 (0) | 2023.03.07 |
---|---|
JSON 명명 규칙(snake_case, camelCase 또는 PascalCase) (0) | 2023.03.07 |
페이지 로드 시 웹 페이지 콘텐츠를 어떻게 div에 로드할 수 있습니까? (0) | 2023.03.07 |
상태가 개체의 배열인 경우 반응 상태를 업데이트하는 중 (0) | 2023.03.07 |
my sql 쿼리를 사용하여 woocommerce에서 완료된 주문을 삭제하는 방법 (0) | 2023.03.07 |