Unblock react history push on particular condition

121 Views Asked by At

When upgrading to React-Router 6 due to some custom architecture around routing and Redux and React-Router removing the Prompt component I had to go with my custom blocking module that was based on history package. I created it within useEffect call as below:

useEffect(() => {
  if (shouldBlock) {
    const unblock = history.block(transition => {
      const url = transition.location.pathname;
      openPromptDialog(url, unblock);
    });
  }
}, [shouldBlock]);

Everything looked like it's working but I found some minor bug. The openPromptDialog opens a custom confirm dialog when we want to leave a page with a dirty form (shouldBlock is true). This part works, but it does not when on the page we save the form and the want to leave. The form is no longer dirty so shouldBlock is false however since it used to be true we didn't have a chance to unblock it and I can't find a way to do it.

Please note that I don't wanna rely on React-Router blocking since I don't (and can't at the moment) use Data API createBrowserRouter which is required in to use useBlocker.

2

There are 2 best solutions below

0
Akeel Ahmed Qureshi On BEST ANSWER

You can try this to unblock variable is declared outside the if (shouldBlock) block and is accessible in the cleanup function. When the component is unmounted or when shouldBlock changes, the cleanup function will be executed, and it will call unblock if it exists. This ensures that the blocking is properly removed even if shouldBlock becomes false.

useEffect(() => {
  let unblock;

  if (shouldBlock) {
    unblock = history.block(transition => {
      const url = transition.location.pathname;
      openPromptDialog(url, () => {
        unblock();
      });
    });
  }

  return () => {
    if (unblock) {
      unblock(); 
    }
  };
}, [shouldBlock]);
0
Drew Reese On

The code you have doesn't ever unblock navigation actions once shouldBlock is set true, e.g. like after it is toggled back to false.

You can return a cleanup function to unblock navigation actions when the shouldBlock dependency updates. This will clean up any previous blockers.

Example:

useEffect(() => {
  if (shouldBlock) {
    const unblock = history.block(transition => {
      const url = transition.location.pathname;
      openPromptDialog(url, unblock);
    });

    return unblock; // <-- unblock as cleanup function when set
  }
}, [shouldBlock]);

Demo

Edit unblock-react-history-push-on-particular-condition