UNPKG

react-router-guard-dirty-state

Version:

Guard unsaved / dirty componets (usually containing forms) by alets when leaving both by onbeforeunload and react-roter routes.

128 lines (111 loc) 5.06 kB
'use strict'; /* * ██████╗ ██╗██████╗ ████████╗██╗ ██╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ * ██╔══██╗██║██╔══██╗╚══██╔══╝╚██╗ ██╔╝ ██╔════╝ ██║ ██║██╔══██╗██╔══██╗██╔══██╗ * ██║ ██║██║██████╔╝ ██║ ╚████╔╝ ██║ ███╗██║ ██║███████║██████╔╝██║ ██║ * ██║ ██║██║██╔══██╗ ██║ ╚██╔╝ ██║ ██║██║ ██║██╔══██║██╔══██╗██║ ██║ * ██████╔╝██║██║ ██║ ██║ ██║ ╚██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝ * ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ */ import React, {Component} from 'react'; let PASS_PROP_AUTO = true; const guardHoc = (UnsavedComponent) => { const getDisplayName = (UnsavedComponent) => { return UnsavedComponent.displayName || UnsavedComponent.name || 'UnsavedComponent'; }; class SaveGuardedComponent extends Component { constructor (props) { super(props); // state holder (stateful) this.state = { guardIsActive: false }; // instance variable holder (stateless) this.instance = { guardIsActive: false }; this.onBeforeUnload = this.onBeforeUnload.bind(this); this.handleGuardSetActive = this.handleGuardSetActive.bind(this); } componentWillUnmount () { window.removeEventListener('beforeunload', this.onBeforeUnload); } onBeforeUnload (ev) { // no custom string possible any more // Chrome: https://developers.google.com/web/updates/2016/04/chrome-51-deprecations?hl=en#remove_custom_messages_in_onbeforeunload_dialogs // anyways, fill it const dialogText = 'Changes you made are not saved. Are you sure you want to leave this page?'; ev.returnValue = dialogText; return dialogText; } // default behaviour is stateful handleGuardSetActive (guardIsActive = false) { console.log('handleGuardSetActive', PASS_PROP_AUTO, guardIsActive); (PASS_PROP_AUTO) ? this.handleGuardSetActiveStateful(guardIsActive) : this.handleGuardSetActiveStateless(guardIsActive); } handleGuardSetActiveStateful (guardIsActive = false) { // if no change made, then just return if (this.state.guardIsActive === guardIsActive) return; // add/remove event listeners if (guardIsActive) { window.addEventListener('beforeunload', this.onBeforeUnload); } else { window.removeEventListener('beforeunload', this.onBeforeUnload); } // Set state (thus - rerender and pass guardIsActive prop) // UnsavedComponent does not have to manage dirty state for Prompt by itself // It can simply use // <Prompt // when={this.props.guardIsActive} // message="Are you sure you want to leave this page?" // /> this.setState({ guardIsActive }); } handleGuardSetActiveStateless (guardIsActive = false) { // if no change made, then just return if (this.instance.guardIsActive === guardIsActive) return; // add/remove event listeners if (guardIsActive) { window.addEventListener('beforeunload', this.onBeforeUnload); } else { window.removeEventListener('beforeunload', this.onBeforeUnload); } // Do not set state (thus - don't rerender and pass guardIsActive prop) // UnsavedComponent has to manage dirty state for Prompt by itself // It has to use // <Prompt // when={this.state.guardIsActive} // message="Are you sure you want to leave this page?" // /> this.instance.guardIsActive = guardIsActive; } render () { if (PASS_PROP_AUTO) { return ( <UnsavedComponent {...this.props} guardDirtySetActive={this.handleGuardSetActive} guardDirtyIsActive={this.state.guardIsActive} /> ); } return ( <UnsavedComponent {...this.props} guardDirtySetActive={this.handleGuardSetActive} /> ); } } SaveGuardedComponent.displayName = `GuardUnsavedComponent(${getDisplayName(UnsavedComponent)})`; return SaveGuardedComponent; }; const guardDirtySate = (supplyGuardDirtyIsActive = true) => { PASS_PROP_AUTO = supplyGuardDirtyIsActive; return guardHoc; }; export default guardDirtySate;