您可以创建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 组件,则数据将被保存并且路由不会改变。