Skip to content

Instantly share code, notes, and snippets.

@RyosukeCla
Last active October 5, 2024 06:14
Show Gist options
  • Save RyosukeCla/fa340b4fc82bb37bd29a1c6ab2769ad3 to your computer and use it in GitHub Desktop.
Save RyosukeCla/fa340b4fc82bb37bd29a1c6ab2769ad3 to your computer and use it in GitHub Desktop.
import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
const prefix = 'vue-router-event';
const vueRouterGoHook = `${prefix}-go`;
const vueRouterReplaceHook = `${prefix}-go`;
const vueRouterPushHook = `${prefix}-push`;
/**
* /packages/front で管理されてる vuejs 内で動いている vue-router との integration
* vue-router から event が送られてきたらときに、こちらで history api を使用する
*/
function VueRouterHook() {
const hisotry = useHistory<{ fromVueRouter?: boolean }>();
const onGoHook = (event: CustomEvent<{ n: number }>) => {
console.log('[React] onGo', event.detail.n);
hisotry.go(event.detail.n);
};
const onReplaceHook = (event: CustomEvent<{ location: string }>) => {
console.log('[React] onReplace', event.detail.location);
hisotry.replace(event.detail.location, { fromVueRouter: true });
};
const onPushHook = (event: CustomEvent<{ location: string }>) => {
console.log('[React] onPush', event.detail.location);
hisotry.push(event.detail.location, { fromVueRouter: true });
};
useEffect(() => {
window.addEventListener(vueRouterGoHook, onGoHook as any);
window.addEventListener(vueRouterReplaceHook, onReplaceHook as any);
window.addEventListener(vueRouterPushHook, onPushHook as any);
/**
* vue router に event を送る。
*/
hisotry.listen((location, action) => {
/**
* push, replace かつ、vue router 起因の場合は skip する。
*/
if (action !== 'POP' && location.state?.fromVueRouter) return;
console.log('[React] dispatch', location.pathname + location.search + location.hash);
window.dispatchEvent(
new CustomEvent('react-router-event-transition-to', {
detail: {
location: location.pathname + location.search + location.hash,
},
})
);
});
return () => {
window.removeEventListener(vueRouterGoHook, onGoHook as any);
window.removeEventListener(vueRouterReplaceHook, onReplaceHook as any);
window.removeEventListener(vueRouterPushHook, onPushHook as any);
}
}, []);
return null;
}
export default VueRouterHook;
import Router, { Route, RawLocation, RouterOptions } from 'vue-router';
/**
* from
* https://github.com/vuejs/vue-router/blob/90cd2690d59c6bd56e5bc12b5b752166a1d35e98/src/history/html5.js#L39-L41
*/
type ExposedRouter = Router & {
match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
}
type BaseHistory = {
router: ExposedRouter;
base: string;
current: Route;
pending?: Route;
cb: (r: Route) => void;
ready: boolean;
readyCbs: Array<Function>;
readyErrorCbs: Array<Function>;
errorCbs: Array<Function>;
listen: (cb: Function) => void;
onReady: (cb: Function, errorCb?: Function) => void;
onError: (errorCb: Function) => void;
transitionTo: (location: RawLocation, onComplete?: (route: Route) => void, onAbort?: Function) => void;
confirmTransition: (route: Route, onComplete: Function, onAbort?: Function) => void;
updateRoute: (route: Route) => void;
}
type SubHistory = BaseHistory & {
push: (location: RawLocation, onComplete?: Function, onAbort?: Function) => void;
go: (n: number) => void;
replace: (location: RawLocation, onComplete?: Function, onAbort?: Function) => void;
getCurrentLocation: () => string;
ensureURL: (push?: boolean) => void;
}
type AbstractHistory = SubHistory & {
stack: string[];
index: number; // default := -1;
}
type ExposedVueRouter = Router & {
history: AbstractHistory;
options: RouterOptions;
};
function hackHistoryInVueRouter(vueRouter: ExposedVueRouter) {
/**
* react router の変更が走ったら、vue router で transition する。
*/
const onReactRouterEventTransitionTo = (event: CustomEvent<{ location: string }>) => {
console.log('[Vue] onTransitionTo', event.detail.location);
vueRouter.history.transitionTo(event.detail.location, (route) => {
console.log('[Vue] transitioned', event.detail.location, route.name);
}, (err: any) => {
if (err) console.log(`[Vue] error, ${err}`);
});
}
window.addEventListener('react-router-event-transition-to', onReactRouterEventTransitionTo as any);
/**
* history の動作を変更する
*/
vueRouter.history.getCurrentLocation = () => {
return window.location.pathname + window.location.search + window.location.hash
}
vueRouter.history.go = (n) => {
dispatch('go', { n });
}
vueRouter.history.push = (location, onComplete, onAbort) => {
vueRouter.history.transitionTo(
location,
(route) => {
dispatch('push', { location: route.fullPath });
onComplete && onComplete(route);
},
onAbort
);
}
vueRouter.history.replace = (location, onComplete, onAbort) => {
vueRouter.history.transitionTo(
location,
(route) => {
dispatch('replace', { location: route.fullPath });
onComplete && onComplete(route);
},
onAbort,
);
}
/**
* https://github.com/vuejs/vue-router/blob/90cd2690d59c6bd56e5bc12b5b752166a1d35e98/src/index.js#L102
* abstract だと初期化されないので、ここでする。
*/
vueRouter.history.transitionTo(
vueRouter.history.getCurrentLocation()
);
}
function dispatch(eventName: 'go' | 'replace' | 'push', detail: any) {
window.dispatchEvent(new CustomEvent(`vue-router-event-${eventName}`, {
detail: detail,
}));
}
export {
hackHistoryInVueRouter
}

Vue 2x in React with React Router 5x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment