Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/reactant-module/src/core/createState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Reducer, Action, AnyAction } from 'redux';
import type { Reducer, Action, AnyAction } from 'redux';

/**
* ## Description
Expand Down
78 changes: 30 additions & 48 deletions packages/reactant-router/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
connectRouter,
ConnectedRouter,
CALL_HISTORY_METHOD,
LOCATION_CHANGE,
RouterAction,
onLocationChanged,
routerActions,
} from 'connected-react-router';
import type { Location, LocationState, Action, History } from 'history';

Expand Down Expand Up @@ -46,30 +46,17 @@ export interface IRouterOptions {
@injectable({
name: 'Router',
})
abstract class BaseReactantRouter extends PluginModule {
readonly [storeKey]?: Store;

abstract class ReactantRouter extends PluginModule {
autoProvide: boolean;

protected history!: History;

abstract push(path: string, state?: Record<string, any>): void;

abstract replace(
path: string,
state?: Record<string, any>
): Promise<void> | void;

abstract go(n: number): Promise<void> | void;

abstract goBack(): Promise<void> | void;

abstract goForward(): Promise<void> | void;

autoCreateHistory: boolean;

onLocationChanged = onLocationChanged;

routerActions = routerActions;

protected readonly stateKey = 'router';

constructor(@inject(RouterOptions) protected options: IRouterOptions) {
Expand All @@ -81,15 +68,9 @@ abstract class BaseReactantRouter extends PluginModule {
this.history = this.options.createHistory();
this.middleware = (store) => (next) => (action: RouterAction) => {
if (action.type !== CALL_HISTORY_METHOD) {
if (
action.type === LOCATION_CHANGE &&
action?.payload?.isFirstRendering === false &&
this.history.location !== action.payload.location
) {
this.history.replace(action.payload.location);
}
return next(action);
}
// Just call `history` method and `history` will change routing, then trigger `history.listen`, and dispatch LOCATION_CHANGE action
const {
payload: { method, args = [] },
} = action;
Expand All @@ -99,61 +80,62 @@ abstract class BaseReactantRouter extends PluginModule {
}
}

get store() {
return this[storeKey];
}

beforeCombineRootReducers(reducers: ReducersMapObject): ReducersMapObject {
if (!this.autoCreateHistory) return reducers;
if (Object.prototype.hasOwnProperty.call(reducers, this.stateKey)) {
throw new Error(
`The identifier '${this.stateKey}' has a duplicate name, please reset the option 'stateKey' of 'ReactantRouter' module.`
);
}
return Object.assign(reducers, {
[this.stateKey]: connectRouter(this.history),
[this.stateKey]: connectRouter(this.history ?? this.defaultHistory),
});
}

protected defaultHistory?: {
location: History['location'];
action: string;
};

ConnectedRouter: FunctionComponent = (props) => (
<ConnectedRouter history={this.history}>{props.children}</ConnectedRouter>
);

get router(): RouterState {
return this[storeKey]?.getState()[this.stateKey];
get router(): RouterState | undefined {
return this.store?.getState()[this.stateKey];
}

get currentPath() {
return this.router?.location.pathname;
}

provider = (props: PropsWithChildren<any>) => {
if (!this.autoProvide) return props.children;
return <this.ConnectedRouter>{props.children}</this.ConnectedRouter>;
};
}

@injectable()
class ReactantRouter extends BaseReactantRouter {
constructor(@inject(RouterOptions) public options: IRouterOptions) {
super(options);
}

push(path: string, state?: Record<string, any>) {
this.history.push(path, state);
push(path: string, state?: LocationState) {
this.store?.dispatch(this.routerActions.push(path, state));
}

replace(path: string, state?: Record<string, any>) {
this.history.replace(path, state);
replace(path: string, state?: LocationState) {
this.store?.dispatch(this.routerActions.replace(path, state));
}

go(n: number) {
this.history.go(n);
this.store?.dispatch(this.routerActions.go(n));
}

goBack() {
this.history.goBack();
this.store?.dispatch(this.routerActions.goBack());
}

goForward() {
this.history.goForward();
this.store?.dispatch(this.routerActions.goForward());
}

provider = (props: PropsWithChildren<any>) => {
if (!this.autoProvide) return props.children;
return <this.ConnectedRouter>{props.children}</this.ConnectedRouter>;
};
}

export { ReactantRouter as Router, RouterOptions, BaseReactantRouter };
export { ReactantRouter as Router, RouterOptions };
3 changes: 1 addition & 2 deletions packages/reactant-share/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ export const preloadedStateActionName = '@@reactant:preloadedState';
export const isClientName = '@@reactant:isClient';
export const loadFullStateActionName = '@@reactant:loadFullState';
export const syncRouterName = '@@reactant:syncRouter';
export const syncRouterWorkerName = '@@reactant:syncRouterWorker';
// Server to Client
export const proxyServerActionName = '@@reactant:proxyServer';
export const lastActionName = '@@reactant:lastAction';
export const routerChangeName = '@@reactant:routerChange';
export const syncToClientsName = '@@reactant:syncToClients';
export const syncWorkerRouterName = '@@reactant:syncWorkerRouter';

export const SharedAppOptions = Symbol('SharedAppOptions');
23 changes: 7 additions & 16 deletions packages/reactant-share/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
/* eslint-disable no-use-before-define */
import type { EmitParameter, Transport } from 'data-transport';
import type { Config as BaseConfig, App, Renderer } from 'reactant';
import type { ILastActionState } from 'reactant-last-action';
import type { Router, RouterState } from 'reactant-router';
import type { RouterState } from 'reactant-router';
import {
isClientName,
lastActionName,
loadFullStateActionName,
preloadedStateActionName,
proxyClientActionName,
proxyServerActionName,
routerChangeName,
syncRouterName,
syncRouterWorkerName,
syncWorkerRouterName,
syncToClientsName,
} from './constants';
import type { RouterChangeNameOptions } from './router';

export type { Transport } from 'data-transport';

Expand Down Expand Up @@ -72,6 +71,8 @@ export interface ISharedAppOptions {
* Forced Sync for all client, enabled by default.
*
* If forcedSyncClient is false, then only the client's visibilityState is visible will the state be synchronized from server port.
*
* `forcedSyncClient` is only true in `SharedTab` type.
*/
forcedSyncClient?: boolean;
}
Expand Down Expand Up @@ -108,8 +109,7 @@ export interface ClientTransport {
sequence: number
): Promise<Record<string, any> | null | undefined>;
[isClientName](): Promise<boolean>;
[syncRouterName](name: string): Promise<RouterState>;
[syncRouterWorkerName](router: Router['router'], name: string): void;
[syncRouterName](name: string, router?: RouterState): Promise<RouterState>;
}

export type ActionOptions = Pick<
Expand All @@ -124,12 +124,10 @@ export interface ServerTransport {
args: any[];
}): Promise<void>;
[lastActionName](options: ActionOptions): Promise<void>;
[routerChangeName](
options: RouterChangeNameOptions
): Promise<RouterState | null>;
[syncToClientsName](
options: Record<string, any> | null | undefined
): Promise<void>;
[syncWorkerRouterName](name: string): Promise<RouterState | undefined>;
}

export interface HandleServerOptions {
Expand All @@ -156,13 +154,6 @@ export type FunctionKeys<T> = Exclude<
void
>;

interface SpawnOptions {
/**
* Spawn transport, and default transport is client
*/
port?: Port;
}

export type ProxyExec = <
T extends Record<string | number | symbol, any>,
K extends FunctionKeys<T>,
Expand Down
4 changes: 4 additions & 0 deletions packages/reactant-share/src/portDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ export class PortDetector {
return this.sharedAppOptions.type === 'SharedWorker';
}

get isServerWorker() {
return this.isWorkerMode && this.isServer;
}

get isServer() {
return !!this.detectPort('server');
}
Expand Down
Loading