首页 > 解决方案 > 在 React Router v6 中,如何在离开页面/路由之前检查表单是否脏

问题描述

以下是我正在使用的软件包版本。

React version - 16.13.1
react-router-dom version - 6.0.0-beta.0
react-redux version 7.2.0
Material UI version 4.11.0

isDirty当用户试图离开当前页面时,如何/什么是检查表单(已更改)的最佳方法?如果表格是isDirty.

我将从内部获取数据useEffect()并使用 redux reducer 来呈现 UI。

我应该声明一个变量来保留原始获取的数据以进行脏检查吗?

这就是我正在做的,但它不能正常工作。

组件.js

 useEffect(() => {
    props.fetchUserInfo();
 })

动作.js

export function fetchUserInfo() {
 return (dispatch) => {
     dispatch({type: USER_INITIALSTATE, {Name: 'abc', Age: 20}} 
     )
 }
}

userReducer.js

const initialState = {
  processing: false,
  success: false,
  fail: false,
  Profile: {}
}
let oriState;
let State;
const UserReducer = (state = initialState, action) => {
  if (action.type === USER_INITIALSTATE) {
    oriState = {Profile: action.data};
    State = {...state, Profile: action.data};
    return {...state, Profile: action.data};
  } else if (action.type === OTHERS_ACTION) {
     //update field change
     return {...state, xxx}
  }
}
export const userIsDirty = state => {
  if (oriState && State) {
    return JSON.stringify(oriState.Profile) !== JSON.stringify(State.Profile);
  }
  return false;
};
export default UserReducer;

因此,在我的组件中,我调用userIsDirty返回 isDirty 布尔值,但我还没有弄清楚如何捕获离开页面事件并将其用作触发器来进行脏表单检查。

那么如何检测离开当前页面呢?我在useEffect return(component umount)上尝试了一些东西,但是道具没有获得更新的INITIALSTATE状态(意味着我将获得Profile:{}),因为它只运行一次,但是如果我添加useEffect可选数组参数,我得到一个无限循环(也许我设置错了?)。

useEffect(() => {
    props.fetchUserInfo();
    return () => {
      console.log(props); //not getting initial state object
    };
  }, []);

我这样做是正确的方式吗?我错过了什么?是否有更好/正确的解决方案来实现我想要的?

更新

谢谢@gdh,useBlocker是我想要的。我正在使用它来弹出一个确认对话框。

我将分享我完整的代码框,我相信这可能对将来的某人有所帮助。

使用 useBlocker 显示确认对话框

标签: reactjsreact-reduxreact-routermaterial-ui

解决方案


这个答案使用路由器 v6。

  1. 您可以使用usePrompt
  • 当您转到另一条路线(即安装时)时,usePrompt 将显示确认模式/弹出窗口。
  • 当您尝试关闭浏览器时,带有消息的通用警报。它在内部处理 beforeunload
usePrompt("Hello from usePrompt -- Are you sure you want to leave?", isBlocking);
  1. 您可以使用useBlocker
  • useBlocker 将在尝试导航离开时(即卸载时)简单地阻止用户
  • 当您尝试关闭浏览器时,带有消息的通用警报。它在内部处理 beforeunload
useBlocker(
    () => "Hello from useBlocker -- are you sure you want to leave?",
    isBlocking
  );

1 和 2 的演示

  1. 您也可以使用beforeunload。但是你必须做你自己的逻辑。在此处查看示例

推荐阅读