Skip to content

Instantly share code, notes, and snippets.

@moodysalem
Created January 22, 2017 18:52
Show Gist options
  • Save moodysalem/7636ccdfbd21b4f4263f0b8485186733 to your computer and use it in GitHub Desktop.
Save moodysalem/7636ccdfbd21b4f4263f0b8485186733 to your computer and use it in GitHub Desktop.
React HOC to prevent leaving a page
import React, { Component, PropTypes } from 'react';
/**
* Only ever render one of these per page
*
* TODO: improve with react-side-effect to better handle multiple instances of this being rendered at once so we can
* nest the component in forms
*/
export default class PreventLeaveRoute extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
};
static propTypes = {
route: PropTypes.object.isRequired,
locked: PropTypes.bool.isRequired,
text: PropTypes.string
};
static defaultProps = {
text: 'You have unsaved changes. Would you like to continue?'
};
shouldComponentUpdate() {
return false;
}
bindRouteLeaveHook = route => this.context.router.setRouteLeaveHook(route, this.preventRouteLeave);
componentDidMount() {
const { route } = this.props;
this.bindRouteLeaveHook(route);
window.onbeforeunload = this.preventUnload;
}
componentWillReceiveProps({ route }) {
if (route !== this.props.route) {
this.bindRouteLeaveHook(route);
}
}
componentWillUnmount() {
window.onbeforeunload = null;
}
preventUnload = () => {
const { text, locked } = this.props;
if (locked) {
return text;
}
};
preventRouteLeave = ({ action }) => {
const { locked, text } = this.props;
if (locked) {
if (!confirm(text)) {
if (action === 'POP') {
const { router } = this.context;
router.goForward();
}
return false;
} else {
window.onbeforeunload = null;
}
} else {
window.onbeforeunload = null;
}
};
render() {
return null;
}
}
@SimpleCookie
Copy link

SimpleCookie commented Jan 23, 2020

I would recommend revising line 57 - 70. I would like to be diplomatic, but I really hate code like that.
It's beyond unreadable.

I haven't test it. But it can be simplified so much. For example, you could write it like this

  preventRouteLeave = ({ action }) => {
    const { locked, text } = this.props;

    if (!locked || confirm(text)) {
      window.onbeforeunload = null;
      return
    }

    if (action === 'POP') {
      const { router } = this.context;
      router.goForward();
    }
  };

Which is much more readable than this

  preventRouteLeave = ({ action }) => {
    const { locked, text } = this.props;

    if (locked) {
      if (!confirm(text)) {
        if (action === 'POP') {
          const { router } = this.context;
          router.goForward();
        }
        return false;
      } else {
        window.onbeforeunload = null;
      }
    } else {
      window.onbeforeunload = null;
    }
  };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment