【问题标题】:Prevent going back conditionally with react-router-dom 5使用 react-router-dom 5 防止有条件地返回
【发布时间】:2021-08-21 00:59:42
【问题描述】:
useEffect(() => {
    return history.listen(_ => {
        console.log(history.action);
        if (history.action === 'POP' && (location.pathname === Settings_NewPersonPath || location.pathname === Settings_NewBusinessPath) && entityState.data) {
            setEntityState({
                ...entityState,
                submitted: false
            });
        }
    })
}, [])

我正在模拟使用状态的多个页面。但是,当有人在第二个“页面”上并按下返回按钮时,我只想更新状态而不是真正返回。

我该怎么做?

【问题讨论】:

  • 查看this我的回答。
  • @AliBdeir 是否要停止转换到 Settings_NewPersonPath 和 Settings_NewBusinessPath 路由,或者您要先保存数据然后应用路由更改吗?

标签: reactjs react-router react-router-dom


【解决方案1】:

您可以创建Route Context 来处理路由更改,并为那些您需要在更改路由之前保存数据或防止路由更改的组件创建侦听器:

RouteProvider.js

将此组件添加到组件结构的顶部,但在 Router 组件内。

const RouteContext = React.createContext();

const RouteProvider = ({ children }) => {
  const locationKey = useRef({ /* keep tracking the route history */
    to: null,
    from: null,
  });
  const listeners = useRef({});
  const history = useHistory();

  useEffect(() => {
    /* set the locationKey value during the first render*/
    locationKey.current = {
      from: history.location.pathname,
      to: history.location.pathname
    }
    return history.block(({ pathname }, action) => {
      if(locationKey.current.to === pathname) return;
      if (locationKey.current.from === pathname) {
        /** you are going to the last route visited */
        const listenerValues = Object.values(listeners.current);
        listenerValues.forEach(({callback, prevent}) => {
          callback();
        });
        /** if one listener needs to prevent the route changes */
        if(listenerValues.find(({prevent})=> prevent)) return false;
      }
      locationKey.current = { from: locationKey.current.to, to: pathname };    
    });
  }, [history]);

  /* add listeners*/
  const onBackListener = (callback, prevent = false) => {
    const ID = Date.now;
    listeners.current[ID] = {
      callback,
      prevent,
    };
    return ID;
  };

  /* remove listeners*/
  const removeListener = (ID) => delete listeners.current[ID] ;

  return <RouteContext.Provider value={{onBackListener, removeListener}}>{children}</RouteContext.Provider>;
};

SecondComponent.js

此组件将向 RouteContext 添加一个监听器,并防止路由更改。

function Second() {
  const {onBackListener, removeListener} = React.useContext(RouteContext);
  const [state, setState] = useState();

  useEffect(()=> {
     const listener = onBackListener(()=> {
       /**save data */
       console.log("saving data");
       setState("Data")
     }, true);


     return () => removeListener(listener);
  }, []);

  return <h2>Second Page</h2>;
}

我没有测试所有可能的场景,但它会让您了解如何对其进行转换以满足您的要求。

Working example 如果您尝试从 Second 组件转到 Home 组件,则数据将被保存并且路由不会改变。

【讨论】:

    【解决方案2】:

    您可以使用history.block API 来防止页面转换。示例:

    useEffect(() => {
      const unblock = history.block(({ action, location, retry }) => {
        // Conditional state manipulation
        // Call unblock and retry to actually perform transition
      });
    
      return () => {
        unblock();
      };
    }, []);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-24
      • 2019-03-19
      • 1970-01-01
      • 2019-03-22
      • 2020-04-24
      • 2022-06-13
      • 1970-01-01
      • 2020-02-15
      相关资源
      最近更新 更多