Skip to content

Commit ccc45ba

Browse files
committed
feat(reactant-share): support go, goback and goForward in shared app
1 parent 9db5de8 commit ccc45ba

File tree

2 files changed

+157
-45
lines changed

2 files changed

+157
-45
lines changed

packages/reactant-share/src/modules/router.ts

Lines changed: 155 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export interface IRouterOptions extends IBaseRouterOptions {
4545
* default initial route
4646
*/
4747
defaultRoute?: string;
48+
/**
49+
* The maximum number of historical records stored in the browser, the default is 10.
50+
*/
51+
maxHistoryLength?: number;
4852
}
4953

5054
@injectable({
@@ -53,6 +57,10 @@ export interface IRouterOptions extends IBaseRouterOptions {
5357
class ReactantRouter extends BaseReactantRouter {
5458
private passiveRoute = false;
5559

60+
private cachedHistory: RouterState[] = [];
61+
62+
private forwardHistory: RouterState[] = [];
63+
5664
constructor(
5765
protected portDetector: PortDetector,
5866
@inject(SharedAppOptions) protected sharedAppOptions: ISharedAppOptions,
@@ -139,6 +147,19 @@ class ReactantRouter extends BaseReactantRouter {
139147

140148
// #region sync init router from clients in Worker mode
141149
this.portDetector.onServer((transport) => {
150+
watch(
151+
this,
152+
() => this.router,
153+
(router) => {
154+
if (
155+
router?.location.pathname !==
156+
this.cachedHistory[0]?.location?.pathname
157+
) {
158+
this.cachedHistory.unshift(router!);
159+
this.cachedHistory.length = this.maxHistoryLength; // Limit the length of the historical stack
160+
}
161+
}
162+
);
142163
if (this.portDetector.isWorkerMode && !this.enableCacheRouting) {
143164
transport
144165
.emit(syncWorkerRouterName, this.portDetector.name)
@@ -251,6 +272,10 @@ class ReactantRouter extends BaseReactantRouter {
251272
// #endregion
252273
}
253274

275+
get maxHistoryLength() {
276+
return this.options.maxHistoryLength ?? 10;
277+
}
278+
254279
watchRehydratedRouting() {
255280
// The first rendering and the hydration of the persistent router may emit actions in a different order due to the module order.
256281
let firstTrigger = false;
@@ -511,63 +536,148 @@ class ReactantRouter extends BaseReactantRouter {
511536
}
512537
}
513538

514-
async go(n: number) {
515-
if (this.portDetector.isServerWorker) {
516-
const router: RouterState = await fork(
517-
this as any,
518-
'_makeRoutingOnClient',
519-
[
520-
{
521-
args: [n],
522-
action: 'go',
523-
name: this.portDetector.name,
524-
},
525-
]
526-
);
527-
this.dispatchChanged(router);
528-
} else {
539+
async go(n: number): Promise<void> {
540+
if (!this.portDetector.shared) {
529541
this.lastRoutedTimestamp = Date.now();
530542
super.go(n);
543+
return;
531544
}
532-
}
545+
if (this.portDetector.isClient) {
546+
return delegate(this as ReactantRouter, 'go', [n]);
547+
}
548+
if (n < 0) {
549+
// Navigate backward (like goBack)
550+
const stepsBack = Math.abs(n);
551+
if (this.cachedHistory.length > stepsBack) {
552+
// Pop the current route to the forward history stack
553+
const currentRouter = this.cachedHistory.shift();
554+
this.forwardHistory.unshift(currentRouter!); // Add to forward history
533555

534-
async goBack() {
535-
if (this.portDetector.isServerWorker) {
536-
const router: RouterState = await fork(
537-
this as any,
538-
'_makeRoutingOnClient',
539-
[
540-
{
541-
args: [],
542-
action: 'goBack',
543-
name: this.portDetector.name,
544-
},
545-
]
546-
);
547-
this.dispatchChanged(router);
556+
// Get the target router (stepsBack-th item)
557+
const targetRouter = this.cachedHistory[stepsBack - 1];
558+
559+
if (targetRouter) {
560+
const router: RouterState = await fork(
561+
this as any,
562+
'_makeRoutingOnClient',
563+
[
564+
{
565+
args: [
566+
targetRouter.location.pathname,
567+
targetRouter.location.state,
568+
],
569+
action: 'replace',
570+
name: this.portDetector.name,
571+
},
572+
]
573+
);
574+
this.dispatchChanged(router);
575+
} else {
576+
console.warn('No more history to go back.');
577+
}
578+
} else {
579+
console.warn('No more history to go back.');
580+
}
581+
} else if (n > 0) {
582+
// Navigate forward (like goForward)
583+
const stepsForward = n;
584+
if (this.forwardHistory.length >= stepsForward) {
585+
const targetRouter = this.forwardHistory[stepsForward - 1];
586+
if (targetRouter) {
587+
const router: RouterState = await fork(
588+
this as any,
589+
'_makeRoutingOnClient',
590+
[
591+
{
592+
args: [
593+
targetRouter.location.pathname,
594+
targetRouter.location.state,
595+
],
596+
action: 'replace',
597+
name: this.portDetector.name,
598+
},
599+
]
600+
);
601+
this.dispatchChanged(router);
602+
} else {
603+
console.warn('No more history to go forward.');
604+
}
605+
// Remove the used entry from the forward stack
606+
this.forwardHistory.splice(0, stepsForward);
607+
} else {
608+
console.warn('No more history to go forward.');
609+
}
548610
} else {
611+
// Go to the current route (refresh the page)
612+
console.warn('Going to the current route (n = 0) does nothing.');
613+
}
614+
}
615+
616+
async goBack(): Promise<void> {
617+
if (!this.portDetector.shared) {
549618
this.lastRoutedTimestamp = Date.now();
550619
super.goBack();
620+
return;
621+
}
622+
if (this.portDetector.isClient) {
623+
return delegate(this as ReactantRouter, 'goBack', []);
624+
}
625+
if (this.cachedHistory.length > 1) {
626+
const currentRouter = this.cachedHistory.shift(); // Pop the current route
627+
this.forwardHistory.unshift(currentRouter!); // Push to forward stack
628+
this.forwardHistory.length = this.maxHistoryLength; // Limit the length of the forward stack
629+
const previousRouter = this.cachedHistory[0]; // Get the previous route
630+
if (previousRouter) {
631+
const router: RouterState = await fork(
632+
this as any,
633+
'_makeRoutingOnClient',
634+
[
635+
{
636+
args: [
637+
previousRouter.location.pathname,
638+
previousRouter.location.state,
639+
],
640+
action: 'replace',
641+
name: this.portDetector.name,
642+
},
643+
]
644+
);
645+
this.dispatchChanged(router);
646+
} else {
647+
console.warn('No forward route available.');
648+
}
649+
} else {
650+
console.warn('No previous route available.');
551651
}
552652
}
553653

554-
async goForward() {
555-
if (this.portDetector.isServerWorker) {
556-
const router: RouterState = await fork(
557-
this as any,
558-
'_makeRoutingOnClient',
559-
[
560-
{
561-
args: [],
562-
action: 'goForward',
563-
name: this.portDetector.name,
564-
},
565-
]
566-
);
567-
this.dispatchChanged(router);
568-
} else {
654+
async goForward(): Promise<void> {
655+
if (!this.portDetector.shared) {
569656
this.lastRoutedTimestamp = Date.now();
570657
super.goForward();
658+
return;
659+
}
660+
if (this.portDetector.isClient) {
661+
return delegate(this as ReactantRouter, 'goForward', []);
662+
}
663+
if (this.forwardHistory.length > 0) {
664+
const nextRouter = this.forwardHistory.shift(); // Pop from forward stack
665+
if (nextRouter) {
666+
const router: RouterState = await fork(
667+
this as any,
668+
'_makeRoutingOnClient',
669+
[
670+
{
671+
args: [nextRouter.location.pathname, nextRouter.location.state],
672+
action: 'replace',
673+
name: this.portDetector.name,
674+
},
675+
]
676+
);
677+
this.dispatchChanged(router);
678+
}
679+
} else {
680+
console.warn('No forward route available.');
571681
}
572682
}
573683
}

packages/reactant-share/test/router.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,6 +2445,7 @@ describe('Worker - createMemoryHistory', () => {
24452445
.querySelector('#goBack')!
24462446
.dispatchEvent(new MouseEvent('click', { bubbles: true }));
24472447
});
2448+
await Promise.resolve();
24482449
expect(serverApp.instance.router.currentPath).toBe('/');
24492450
expect(clientApp.instance.router.currentPath).toBe('/');
24502451
expect(clientContainer.querySelector('#content')?.textContent).toBe('home');
@@ -2661,6 +2662,7 @@ describe('Worker - createMemoryHistory', () => {
26612662
.querySelector('#goBack')!
26622663
.dispatchEvent(new MouseEvent('click', { bubbles: true }));
26632664
});
2665+
await Promise.resolve();
26642666
expect(app.instance.router.currentPath).toBe('/');
26652667
expect(clientContainer.querySelector('#content')?.textContent).toBe('home');
26662668

0 commit comments

Comments
 (0)