简体   繁体   中英

React functional component - how to ask user to confirm when leaving a component

I have a quite traditional problem but I haven't found a solution thus far searching around on Stackoverflow.

My problem is like this. I have a functional component which renders a form (using Formik). This component is rendered inside another Tab component that allows user to switch to another view. The UI also have another menu, buttons which also allow user to switch to different UI. Whenever a user changes a field in the form, I have a global flag in Redux store that marks it as dirty form.

What I want to achieve is that when user click on another tab or go to another UI view when form is dirty, system will show a dialog to confirm. If user agrees, he loses his changes and go to another view, if he doesn't, he will stay at current view with the form.

My current solution is that I have to add the confirming logic to every event handler that could bring user to another view such as Tab click, Menu click and this is tedious. Not to mention if the UI change in the future with more events for example more buttons, we have to keep adding this confirm logic to the onClick handler.

I also tried using useEffect as below in this component that returns a clean up function where I can add the confirm logic. This could show up the confirm dialog but it won't prevent React to unmount this form component and user ends up still go to another view.

useEffect(() => {
  return () => {
    //confirm logic here
  }
}, [])

Is there a way for functional component handle this confirming logic itself?

These are some post I looked at but don't really find the answer. This one suggest using React router which we don't use in our project. The route actually doesn't change when user leave this form component. Show warning message before unmouting React component

Thanks for any advice!

In short, no. That's a drawback of single page applications. Since the page isn't actually being navigated, you can't use the native beforeunload event, and since you're not using a router you can't customize routing in that respect either. What you can do is wrap these navigation components with a custom component so you don't need to repeat yourself everywhere.

const MyCustomTabComponent = (props) => {
  function navigateIfNotDirty(tabIndex) {
    // Check if it's safe to navigate
    props.onTabChange?.() // Maybe allow passing another callback in as well
    // Finally navigate
  }
  
  return <TabComponent {...props} onTabChange={navigateIfNotDirty} />
}

I don't know the actual syntax of the components you're using, but that should give you the idea.

The actual logic will be specific to the UI library you're using, if any. By your question, it seems like you already figured out how to cancel navigation given a condition, it's just a matter of abstracting that logic into a new, reusable component.

If the navigation components are already custom instead of being from a library, then it's even easier.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM