From 5190bf10130c04ce82cb62312447d8a58f46d378 Mon Sep 17 00:00:00 2001 From: Piotr Date: Wed, 6 Jun 2018 17:02:58 +0200 Subject: [PATCH 01/13] Proposed fix for #2 Proposed fix for #2 --- src/index.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 479bf44..9a3d493 100644 --- a/src/index.js +++ b/src/index.js @@ -90,6 +90,8 @@ class NavigationPrompt extends React.Component { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } + + this.isUnmounted = true } block(nextLocation, action) { @@ -107,7 +109,7 @@ class NavigationPrompt extends React.Component { navigateToNextLocation(cb) { let {action, nextLocation} = this.state; action = { - 'POP': 'push', + 'POP': 'goBack', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; @@ -116,12 +118,25 @@ class NavigationPrompt extends React.Component { this.state.unblock(); // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. - history[action](nextLocation); + + if (action === 'goBack') { + history.goBack(); + } else { + history[action](nextLocation); + } + this._prevUserAction = 'CONFIRM'; - this.setState({ - ...initState, - unblock: this.props.history.block(this.block) - }); // FIXME? Does history.listen need to be used instead, for async? + + // This helps when using in goBack + window.setTimeout(() => { + // There is a change that component has been unmounted after navigation + if (!this.isUnmounted) { + this.setState({ + ...initState, + unblock: this.props.history.block(this.block) + }); // FIXME? Does history.listen need to be used instead, for async? + } + }, 0) } onCancel() { From 45939bf3e475db03f5072b835d6ed593c202c5c7 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 16:43:38 +0200 Subject: [PATCH 02/13] Use async state update only for history.goBack --- es/index.js | 37 ++++++++++++++++++++++++++++++------- src/index.js | 43 +++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/es/index.js b/es/index.js index ed80c1a..ae46675 100644 --- a/es/index.js +++ b/es/index.js @@ -121,6 +121,7 @@ var NavigationPrompt = function (_React$Component) { _inherits(NavigationPrompt, _React$Component); /*:: _prevUserAction: string; */ + /*:: _isUnmounted: boolean; */ function NavigationPrompt(props) { _classCallCheck(this, NavigationPrompt); @@ -131,6 +132,7 @@ var NavigationPrompt = function (_React$Component) { var _this = _possibleConstructorReturn(this, (NavigationPrompt.__proto__ || Object.getPrototypeOf(NavigationPrompt)).call(this, props)); _this._prevUserAction = ''; + _this._isUnmounted = true; _this.block = _this.block.bind(_this); _this.onBeforeUnload = _this.onBeforeUnload.bind(_this); @@ -145,6 +147,7 @@ var NavigationPrompt = function (_React$Component) { _createClass(NavigationPrompt, [{ key: 'componentDidMount', value: function componentDidMount() { + this._isUnmounted = false; if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -170,6 +173,7 @@ var NavigationPrompt = function (_React$Component) { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } + this._isUnmounted = true; } }, { key: 'block', @@ -187,12 +191,14 @@ var NavigationPrompt = function (_React$Component) { }, { key: 'navigateToNextLocation', value: function navigateToNextLocation(cb) { + var _this2 = this; + var _state = this.state, action = _state.action, nextLocation = _state.nextLocation; action = { - 'POP': 'push', + 'POP': 'goBack', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; @@ -201,9 +207,26 @@ var NavigationPrompt = function (_React$Component) { this.state.unblock(); + this._prevUserAction = 'CONFIRM'; + + // Special handling for goBack + if (action === 'goBack') { + history.goBack(); + // As native history.go(-1) exetues after this method has finished, need to update state asychronously + // otherwise it will trigger navigateToNextLocation method again + return window.setTimeout(function () { + // Skip state update when component has been unmounted in meanwhile. Usually this is what happens. + if (!_this2._isUnmounted) { + _this2.setState(_extends({}, initState, { + unblock: _this2.props.history.block(_this2.block) + })); + } + }, 0); + } + // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. history[action](nextLocation); - this._prevUserAction = 'CONFIRM'; + this.setState(_extends({}, initState, { unblock: this.props.history.block(this.block) })); // FIXME? Does history.listen need to be used instead, for async? @@ -211,24 +234,24 @@ var NavigationPrompt = function (_React$Component) { }, { key: 'onCancel', value: function onCancel() { - var _this2 = this; + var _this3 = this; (this.props.beforeCancel || function (cb) { cb(); })(function () { - _this2._prevUserAction = 'CANCEL'; - _this2.setState(_extends({}, initState)); + _this3._prevUserAction = 'CANCEL'; + _this3.setState(_extends({}, initState)); }); } }, { key: 'onConfirm', value: function onConfirm() { - var _this3 = this; + var _this4 = this; (this.props.beforeConfirm || function (cb) { cb(); })(function () { - _this3.navigateToNextLocation(_this3.props.afterConfirm); + _this4.navigateToNextLocation(_this4.props.afterConfirm); }); } }, { diff --git a/src/index.js b/src/index.js index 9a3d493..66a1ffa 100644 --- a/src/index.js +++ b/src/index.js @@ -48,6 +48,7 @@ const initState = { */ class NavigationPrompt extends React.Component { /*:: _prevUserAction: string; */ + /*:: _isUnmounted: boolean; */ constructor(props) { super(props); @@ -56,6 +57,7 @@ class NavigationPrompt extends React.Component { // See: See https://github.com/ZacharyRSmith/react-router-navigation-prompt/pull/9 // I don't like making this an instance var, this._prevUserAction = ''; + this._isUnmounted = true; (this:Object).block = this.block.bind(this); (this:Object).onBeforeUnload = this.onBeforeUnload.bind(this); @@ -67,6 +69,7 @@ class NavigationPrompt extends React.Component { } componentDidMount() { + this._isUnmounted = false if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -90,8 +93,7 @@ class NavigationPrompt extends React.Component { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } - - this.isUnmounted = true + this._isUnmounted = true } block(nextLocation, action) { @@ -117,26 +119,31 @@ class NavigationPrompt extends React.Component { const {history} = this.props; this.state.unblock(); - // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. - + this._prevUserAction = 'CONFIRM'; + + // Special handling for goBack if (action === 'goBack') { history.goBack(); - } else { - history[action](nextLocation); + // As native history.go(-1) exetues after this method has finished, need to update state asychronously + // otherwise it will trigger navigateToNextLocation method again + return window.setTimeout(() => { + // Skip state update when component has been unmounted in meanwhile. Usually this is what happens. + if (!this._isUnmounted) { + this.setState({ + ...initState, + unblock: this.props.history.block(this.block) + }); + } + }, 0); } - this._prevUserAction = 'CONFIRM'; - - // This helps when using in goBack - window.setTimeout(() => { - // There is a change that component has been unmounted after navigation - if (!this.isUnmounted) { - this.setState({ - ...initState, - unblock: this.props.history.block(this.block) - }); // FIXME? Does history.listen need to be used instead, for async? - } - }, 0) + // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. + history[action](nextLocation); + + this.setState({ + ...initState, + unblock: this.props.history.block(this.block) + }); // FIXME? Does history.listen need to be used instead, for async? } onCancel() { From 2db1b0d5a019601a7e077c5c6ee807c0b4d62a78 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 17:00:30 +0200 Subject: [PATCH 03/13] Increase async timeout gor hashHistory --- es/index.js | 2 +- src/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/es/index.js b/es/index.js index ae46675..b9ae33d 100644 --- a/es/index.js +++ b/es/index.js @@ -221,7 +221,7 @@ var NavigationPrompt = function (_React$Component) { unblock: _this2.props.history.block(_this2.block) })); } - }, 0); + }, 25); } // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. diff --git a/src/index.js b/src/index.js index 66a1ffa..5d2e338 100644 --- a/src/index.js +++ b/src/index.js @@ -134,7 +134,7 @@ class NavigationPrompt extends React.Component { unblock: this.props.history.block(this.block) }); } - }, 0); + }, 25); } // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. From 78656461a48599f5b98cc3146bbf23f8536c29c3 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 17:20:35 +0200 Subject: [PATCH 04/13] Revert prevUserAction code position --- es/index.js | 3 ++- src/index.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/es/index.js b/es/index.js index b9ae33d..1459cc2 100644 --- a/es/index.js +++ b/es/index.js @@ -207,11 +207,11 @@ var NavigationPrompt = function (_React$Component) { this.state.unblock(); - this._prevUserAction = 'CONFIRM'; // Special handling for goBack if (action === 'goBack') { history.goBack(); + this._prevUserAction = 'CONFIRM'; // As native history.go(-1) exetues after this method has finished, need to update state asychronously // otherwise it will trigger navigateToNextLocation method again return window.setTimeout(function () { @@ -226,6 +226,7 @@ var NavigationPrompt = function (_React$Component) { // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. history[action](nextLocation); + this._prevUserAction = 'CONFIRM'; this.setState(_extends({}, initState, { unblock: this.props.history.block(this.block) diff --git a/src/index.js b/src/index.js index 5d2e338..d8f9f53 100644 --- a/src/index.js +++ b/src/index.js @@ -119,11 +119,11 @@ class NavigationPrompt extends React.Component { const {history} = this.props; this.state.unblock(); - this._prevUserAction = 'CONFIRM'; // Special handling for goBack if (action === 'goBack') { history.goBack(); + this._prevUserAction = 'CONFIRM'; // As native history.go(-1) exetues after this method has finished, need to update state asychronously // otherwise it will trigger navigateToNextLocation method again return window.setTimeout(() => { @@ -139,6 +139,7 @@ class NavigationPrompt extends React.Component { // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. history[action](nextLocation); + this._prevUserAction = 'CONFIRM'; this.setState({ ...initState, From ad90a2363e298fb5ebbdd4410aadd501ab513b9f Mon Sep 17 00:00:00 2001 From: Benji Parish Date: Tue, 25 Sep 2018 10:27:28 -0500 Subject: [PATCH 05/13] feat: Adding Typescript typings. --- package.json | 3 ++- types/index.d.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 types/index.d.ts diff --git a/package.json b/package.json index 5cc723c..740ac84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-router-navigation-prompt", - "version": "1.6.6", + "version": "1.6.7", "description": "A replacement component for the react-router ``. Allows for more flexible dialogs.", "scripts": { "build": "webpack", @@ -32,6 +32,7 @@ "jsnext:main": "es/index.js", "main": "es/index.js", "module": "es/index.js", + "typings": "types/index.d.ts", "homepage": "https://github.com/ZacharyRSmith/react-router-navigation-prompt#readme", "peerDependencies": { "react": ">= 15", diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..f763ee5 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,44 @@ +import * as React from 'react'; +import * as H from 'history'; +import { RouteComponentProps, Omit } from 'react-router'; + +declare module 'react-router-navigation-prompt' { + export interface ChildData { + isActive: boolean; + onCancel: () => void; + onConfirm: () => void; + } + + export interface NavigationPromptProps extends RouteComponentProps { + children: (data: ChildData) => React.ReactNode; + when: boolean | ((currentLocation: H.Location, nextLocation?: H.Location) => boolean); + afterCancel?: () => void; + afterConfirm?: () => void; + beforeCancel?: () => void; + beforeConfirm?: () => void; + renderIfNotActive?: boolean; + disableNative?: boolean; + } + + interface NavigationPromptState { + action?: H.Action; + nextLocation?: H.Location; + isActive: boolean; + unblock: () => void; + } + + export class NavigationPrompt extends React.Component { + _prevUserAction: string; + _isMounted: boolean; + + block(nextLocation: H.Location, action: H.Action): boolean; + navigateToNextLocation(cb: () => void): void; + onCancel(): void; + onConfirm(): void; + onBeforeUnload(e: any): string + when(nextLocation?: H.Location): boolean; + } +} + +// This is for the withRouter HOC being used as the default export. +export default function NavigationPrompt(): React.Component>>; From 5ffade232d9d5109e3f90c1caa8cfe7b4c02812b Mon Sep 17 00:00:00 2001 From: "Zachary R. Smith" Date: Wed, 26 Sep 2018 08:46:12 -0500 Subject: [PATCH 06/13] bump: package.json ver --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3634a8..d56e5fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.7.0] - 2018-09-26 +### Added +- Typescript typings + ## [1.6.6] - 2018-09-15 ### Added - Note in README.md that BrowserHistory is supported, but not HashHistory diff --git a/package.json b/package.json index 740ac84..2522bc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-router-navigation-prompt", - "version": "1.6.7", + "version": "1.7.0", "description": "A replacement component for the react-router ``. Allows for more flexible dialogs.", "scripts": { "build": "webpack", From 5012d5ec3eecb1de0def82b3654a31905175bb86 Mon Sep 17 00:00:00 2001 From: Piotr Date: Wed, 6 Jun 2018 17:02:58 +0200 Subject: [PATCH 07/13] Proposed fix for #2 Proposed fix for #2 --- src/index.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 8d92f00..d9e091f 100644 --- a/src/index.js +++ b/src/index.js @@ -113,7 +113,7 @@ class NavigationPrompt extends React.Component { navigateToNextLocation(cb) { let {action, nextLocation} = this.state; action = { - 'POP': 'push', + 'POP': 'goBack', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; @@ -121,6 +121,23 @@ class NavigationPrompt extends React.Component { const {history} = this.props; this.state.unblock(); + + if (action === 'goBack') { + history.goBack(); + this._prevUserAction = 'CONFIRM'; + // This helps when using in goBack + window.setTimeout(() => { + // There is a change that component has been unmounted after navigation + if (this.isMounted) { + this.setState({ + ...initState, + unblock: this.props.history.block(this.block) + }); // FIXME? Does history.listen need to be used instead, for async? + } + }, 0) + return + } + // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. history[action](nextLocation); // could unmount at this point this._prevUserAction = 'CONFIRM'; From 4fa64cde35a328aa8bd16dc380e37c61b2e8cc52 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 16:43:38 +0200 Subject: [PATCH 08/13] Use async state update only for history.goBack --- es/index.js | 40 ++++++++++++++++++++++++++++++++++------ src/index.js | 18 +++++++++++------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/es/index.js b/es/index.js index 9d917db..ec226d2 100644 --- a/es/index.js +++ b/es/index.js @@ -122,6 +122,7 @@ var NavigationPrompt = function (_React$Component) { /*:: _prevUserAction: string; */ /*:: _isMounted: bool; */ + /*:: _isUnmounted: boolean; */ function NavigationPrompt(props) { _classCallCheck(this, NavigationPrompt); @@ -132,6 +133,7 @@ var NavigationPrompt = function (_React$Component) { var _this = _possibleConstructorReturn(this, (NavigationPrompt.__proto__ || Object.getPrototypeOf(NavigationPrompt)).call(this, props)); _this._prevUserAction = ''; + _this._isUnmounted = true; // This component could be used from inside a page, and therefore could be // mounted/unmounted when the route changes. @@ -150,6 +152,7 @@ var NavigationPrompt = function (_React$Component) { _createClass(NavigationPrompt, [{ key: 'componentDidMount', value: function componentDidMount() { + this._isUnmounted = false; if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -176,6 +179,7 @@ var NavigationPrompt = function (_React$Component) { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } + this._isUnmounted = true; } }, { key: 'block', @@ -193,12 +197,14 @@ var NavigationPrompt = function (_React$Component) { }, { key: 'navigateToNextLocation', value: function navigateToNextLocation(cb) { + var _this2 = this; + var _state = this.state, action = _state.action, nextLocation = _state.nextLocation; action = { - 'POP': 'push', + 'POP': 'goBack', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; @@ -207,6 +213,23 @@ var NavigationPrompt = function (_React$Component) { this.state.unblock(); + this._prevUserAction = 'CONFIRM'; + + // Special handling for goBack + if (action === 'goBack') { + history.goBack(); + // As native history.go(-1) exetues after this method has finished, need to update state asychronously + // otherwise it will trigger navigateToNextLocation method again + return window.setTimeout(function () { + // Skip state update when component has been unmounted in meanwhile. Usually this is what happens. + if (!_this2._isUnmounted) { + _this2.setState(_extends({}, initState, { + unblock: _this2.props.history.block(_this2.block) + })); + } + }, 0); + } + // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. history[action](nextLocation); // could unmount at this point this._prevUserAction = 'CONFIRM'; @@ -216,28 +239,33 @@ var NavigationPrompt = function (_React$Component) { unblock: this.props.history.block(this.block) })); // FIXME? Does history.listen need to be used instead, for async? } + history[action](nextLocation); + + this.setState(_extends({}, initState, { + unblock: this.props.history.block(this.block) + })); // FIXME? Does history.listen need to be used instead, for async? } }, { key: 'onCancel', value: function onCancel() { - var _this2 = this; + var _this3 = this; (this.props.beforeCancel || function (cb) { cb(); })(function () { - _this2._prevUserAction = 'CANCEL'; - _this2.setState(_extends({}, initState)); + _this3._prevUserAction = 'CANCEL'; + _this3.setState(_extends({}, initState)); }); } }, { key: 'onConfirm', value: function onConfirm() { - var _this3 = this; + var _this4 = this; (this.props.beforeConfirm || function (cb) { cb(); })(function () { - _this3.navigateToNextLocation(_this3.props.afterConfirm); + _this4.navigateToNextLocation(_this4.props.afterConfirm); }); } }, { diff --git a/src/index.js b/src/index.js index d9e091f..d8ae2b4 100644 --- a/src/index.js +++ b/src/index.js @@ -49,6 +49,7 @@ const initState = { class NavigationPrompt extends React.Component { /*:: _prevUserAction: string; */ /*:: _isMounted: bool; */ + /*:: _isUnmounted: boolean; */ constructor(props) { super(props); @@ -57,6 +58,7 @@ class NavigationPrompt extends React.Component { // See: See https://github.com/ZacharyRSmith/react-router-navigation-prompt/pull/9 // I don't like making this an instance var, this._prevUserAction = ''; + this._isUnmounted = true; // This component could be used from inside a page, and therefore could be // mounted/unmounted when the route changes. @@ -72,6 +74,7 @@ class NavigationPrompt extends React.Component { } componentDidMount() { + this._isUnmounted = false if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -122,20 +125,21 @@ class NavigationPrompt extends React.Component { this.state.unblock(); + // Special handling for goBack if (action === 'goBack') { history.goBack(); this._prevUserAction = 'CONFIRM'; - // This helps when using in goBack - window.setTimeout(() => { - // There is a change that component has been unmounted after navigation - if (this.isMounted) { + // As native history.go(-1) exetues after this method has finished, need to update state asychronously + // otherwise it will trigger navigateToNextLocation method again + return window.setTimeout(() => { + // Skip state update when component has been unmounted in meanwhile. Usually this is what happens. + if (this._isMounted) { this.setState({ ...initState, unblock: this.props.history.block(this.block) - }); // FIXME? Does history.listen need to be used instead, for async? + }); } - }, 0) - return + }, 0); } // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. From 31ef2710d4a7c40932ac9a4198ae3bafb17cde23 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 17:00:30 +0200 Subject: [PATCH 09/13] Increase async timeout gor hashHistory --- es/index.js | 2 +- src/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/es/index.js b/es/index.js index ec226d2..e549450 100644 --- a/es/index.js +++ b/es/index.js @@ -227,7 +227,7 @@ var NavigationPrompt = function (_React$Component) { unblock: _this2.props.history.block(_this2.block) })); } - }, 0); + }, 25); } // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. diff --git a/src/index.js b/src/index.js index d8ae2b4..4addf86 100644 --- a/src/index.js +++ b/src/index.js @@ -139,7 +139,7 @@ class NavigationPrompt extends React.Component { unblock: this.props.history.block(this.block) }); } - }, 0); + }, 25); } // $FlowFixMe history.replace()'s type expects LocationShape even though it works with Location. From d6363df464ce81338859f1c8d4c5cecc154501b1 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sat, 9 Jun 2018 17:20:35 +0200 Subject: [PATCH 10/13] Revert prevUserAction code position --- es/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/es/index.js b/es/index.js index e549450..779d19f 100644 --- a/es/index.js +++ b/es/index.js @@ -213,11 +213,11 @@ var NavigationPrompt = function (_React$Component) { this.state.unblock(); - this._prevUserAction = 'CONFIRM'; // Special handling for goBack if (action === 'goBack') { history.goBack(); + this._prevUserAction = 'CONFIRM'; // As native history.go(-1) exetues after this method has finished, need to update state asychronously // otherwise it will trigger navigateToNextLocation method again return window.setTimeout(function () { @@ -240,6 +240,7 @@ var NavigationPrompt = function (_React$Component) { })); // FIXME? Does history.listen need to be used instead, for async? } history[action](nextLocation); + this._prevUserAction = 'CONFIRM'; this.setState(_extends({}, initState, { unblock: this.props.history.block(this.block) From a0e3c4221bf3b4e701c6763c87bc8cd1167417e0 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sun, 30 Sep 2018 04:05:59 +0200 Subject: [PATCH 11/13] Rebuild after rebase --- es/index.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/es/index.js b/es/index.js index 779d19f..cb2db57 100644 --- a/es/index.js +++ b/es/index.js @@ -179,7 +179,6 @@ var NavigationPrompt = function (_React$Component) { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } - this._isUnmounted = true; } }, { key: 'block', @@ -222,7 +221,7 @@ var NavigationPrompt = function (_React$Component) { // otherwise it will trigger navigateToNextLocation method again return window.setTimeout(function () { // Skip state update when component has been unmounted in meanwhile. Usually this is what happens. - if (!_this2._isUnmounted) { + if (_this2._isMounted) { _this2.setState(_extends({}, initState, { unblock: _this2.props.history.block(_this2.block) })); @@ -239,12 +238,6 @@ var NavigationPrompt = function (_React$Component) { unblock: this.props.history.block(this.block) })); // FIXME? Does history.listen need to be used instead, for async? } - history[action](nextLocation); - this._prevUserAction = 'CONFIRM'; - - this.setState(_extends({}, initState, { - unblock: this.props.history.block(this.block) - })); // FIXME? Does history.listen need to be used instead, for async? } }, { key: 'onCancel', From 73748183f26ebd2076c44d76ea31da3aa7b25be2 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sun, 30 Sep 2018 17:40:54 +0200 Subject: [PATCH 12/13] Adding allowGoBack option --- README.md | 1 + es/index.js | 5 +---- src/index.js | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 87f5482..afac666 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ import Modal from "./your-own-code"; - renderIfNotActive: bool, - when: bool | (Location, ?Location) => bool, - disableNative: bool, + - allowGoBack: bool (use _goBack_ method instead of _push_ when navigating back one or more items), // Added by react-router: - match: Match, - history: RouterHistory, diff --git a/es/index.js b/es/index.js index cb2db57..26fbd7e 100644 --- a/es/index.js +++ b/es/index.js @@ -122,7 +122,6 @@ var NavigationPrompt = function (_React$Component) { /*:: _prevUserAction: string; */ /*:: _isMounted: bool; */ - /*:: _isUnmounted: boolean; */ function NavigationPrompt(props) { _classCallCheck(this, NavigationPrompt); @@ -133,7 +132,6 @@ var NavigationPrompt = function (_React$Component) { var _this = _possibleConstructorReturn(this, (NavigationPrompt.__proto__ || Object.getPrototypeOf(NavigationPrompt)).call(this, props)); _this._prevUserAction = ''; - _this._isUnmounted = true; // This component could be used from inside a page, and therefore could be // mounted/unmounted when the route changes. @@ -152,7 +150,6 @@ var NavigationPrompt = function (_React$Component) { _createClass(NavigationPrompt, [{ key: 'componentDidMount', value: function componentDidMount() { - this._isUnmounted = false; if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -203,7 +200,7 @@ var NavigationPrompt = function (_React$Component) { nextLocation = _state.nextLocation; action = { - 'POP': 'goBack', + 'POP': this.props.useGoBackForPop ? 'goBack' : 'push', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; diff --git a/src/index.js b/src/index.js index 4addf86..40fd877 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,7 @@ declare type PropsT = { renderIfNotActive: bool, when: bool | (Location, ?Location) => bool, disableNative: bool, + allowGoBack: bool, }; declare type StateT = { action: ?HistoryAction, @@ -49,7 +50,6 @@ const initState = { class NavigationPrompt extends React.Component { /*:: _prevUserAction: string; */ /*:: _isMounted: bool; */ - /*:: _isUnmounted: boolean; */ constructor(props) { super(props); @@ -58,7 +58,6 @@ class NavigationPrompt extends React.Component { // See: See https://github.com/ZacharyRSmith/react-router-navigation-prompt/pull/9 // I don't like making this an instance var, this._prevUserAction = ''; - this._isUnmounted = true; // This component could be used from inside a page, and therefore could be // mounted/unmounted when the route changes. @@ -74,7 +73,6 @@ class NavigationPrompt extends React.Component { } componentDidMount() { - this._isUnmounted = false if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -116,7 +114,7 @@ class NavigationPrompt extends React.Component { navigateToNextLocation(cb) { let {action, nextLocation} = this.state; action = { - 'POP': 'goBack', + 'POP': this.props.allowGoBack ? 'goBack' : 'push', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; From 8f2aaaaba23f622f711d190d6095d75bf56364a2 Mon Sep 17 00:00:00 2001 From: Piotr Konieczny Date: Sun, 30 Sep 2018 17:49:15 +0200 Subject: [PATCH 13/13] Switch _isUnmounted to _isMounted --- es/index.js | 9 +++++---- src/index.js | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/es/index.js b/es/index.js index 4cc9abe..2814e2e 100644 --- a/es/index.js +++ b/es/index.js @@ -132,7 +132,10 @@ var NavigationPrompt = function (_React$Component) { var _this = _possibleConstructorReturn(this, (NavigationPrompt.__proto__ || Object.getPrototypeOf(NavigationPrompt)).call(this, props)); _this._prevUserAction = ''; - _this._isUnmounted = true; + + // This component could be used from inside a page, and therefore could be + // mounted/unmounted when the route changes. + _this._isMounted = true; _this.block = _this.block.bind(_this); _this.onBeforeUnload = _this.onBeforeUnload.bind(_this); @@ -147,7 +150,6 @@ var NavigationPrompt = function (_React$Component) { _createClass(NavigationPrompt, [{ key: 'componentDidMount', value: function componentDidMount() { - this._isUnmounted = false; if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -174,7 +176,6 @@ var NavigationPrompt = function (_React$Component) { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } - this._isUnmounted = true; } }, { key: 'block', @@ -199,7 +200,7 @@ var NavigationPrompt = function (_React$Component) { nextLocation = _state.nextLocation; action = { - 'POP': this.props.useGoBackForPop ? 'goBack' : 'push', + 'POP': this.props.allowGoBack ? 'goBack' : 'push', 'PUSH': 'push', 'REPLACE': 'replace' }[action || 'PUSH']; diff --git a/src/index.js b/src/index.js index 4040ffa..40fd877 100644 --- a/src/index.js +++ b/src/index.js @@ -73,7 +73,6 @@ class NavigationPrompt extends React.Component { } componentDidMount() { - this._isUnmounted = false if (!this.props.disableNative) { window.addEventListener('beforeunload', this.onBeforeUnload); } @@ -98,7 +97,6 @@ class NavigationPrompt extends React.Component { if (!this.props.disableNative) { window.removeEventListener('beforeunload', this.onBeforeUnload); } - this._isUnmounted = true } block(nextLocation, action) {