Skip to content

Commit

Permalink
refactor(packages): @sa/simple-router: stable useRoute
Browse files Browse the repository at this point in the history
  • Loading branch information
mufeng889 committed Sep 14, 2024
1 parent cfe46ea commit 6cf09f9
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 37 deletions.
26 changes: 22 additions & 4 deletions packages/simple-router/src/Component.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { RouterProvider as Provider } from 'react-router-dom';
import { useLayoutEffect, useState } from 'react';
import { RouterContext } from './hooks/useRouter';
import { RouteContext } from './hooks/useRoute';
import type { Router } from './router';

export type RouterProviderProps = {
Expand All @@ -8,12 +10,28 @@ export type RouterProviderProps = {
};

const RouterProvider = ({ router, fallback }: RouterProviderProps) => {
const [route, setRoute] = useState(
router.resolve(router.reactRouter.state.location, undefined, router.reactRouter.state.matches.at(-1)?.params)
);

useLayoutEffect(
() =>
router.reactRouter.subscribe(state => {
if (state.navigation.state === 'idle') {
setRoute(router.resolve(state.location, undefined, state.matches.at(-1)?.params));
}
}),
[router, setRoute]
);

return (
<RouterContext.Provider value={router}>
<Provider
fallbackElement={fallback}
router={router.reactRouter}
/>
<RouteContext.Provider value={route}>
<Provider
fallbackElement={fallback}
router={router.reactRouter}
/>
</RouteContext.Provider>
</RouterContext.Provider>
);
};
Expand Down
12 changes: 12 additions & 0 deletions packages/simple-router/src/hooks/useRoute/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createContext, useContext } from 'react';
import type { Route } from '../../types';

export const RouteContext = createContext<Route>({} as Route);
export function useRoute() {
const route = useContext(RouteContext);
if (!route) {
throw new Error('useRouter must be used within a Provider');
}

return route;
}
3 changes: 2 additions & 1 deletion packages/simple-router/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useRouter } from './hooks/useRouter';
import { useRoute } from './hooks/useRoute';
import RouterProvider from './Component';
import type { RouteRecordNormalized } from './matcher/types';

export { useRouter, RouterProvider };
export { useRouter, RouterProvider, useRoute };

export { createRouter } from './router';

Expand Down
26 changes: 7 additions & 19 deletions packages/simple-router/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ export function createRouter({ beforeEach, initRoutes, mode, opt, getReactRoutes

let currentRoute = transformLocationToRoute(reactRouter.state.location, reactRouter.state.matches);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
let listeners: (() => void)[] = [];

reactRouter.getBlocker('beforeGuard', onBeforeRouteChange);

reactRouter.subscribe(afterRouteChange);
Expand Down Expand Up @@ -212,9 +209,13 @@ export function createRouter({ beforeEach, initRoutes, mode, opt, getReactRoutes

async function initReady(): Promise<boolean> {
return new Promise((resolved, reject) => {
init(currentRoute.fullPath, blockerOrJump)
.then(() => {
reactRouter.initialize();
init(currentRoute.fullPath)
.then(res => {
if (!res) {
reactRouter.initialize();
} else {
reactRouter.initialize().navigate(resolve(res).fullPath);
}
resolved(true);
})
.catch(e => {
Expand Down Expand Up @@ -277,23 +278,12 @@ export function createRouter({ beforeEach, initRoutes, mode, opt, getReactRoutes
return getRoutes().find(route => route.name === key)?.meta;
}

function getSnapshot() {
return currentRoute;
}

function resetRoute() {
// Resets the route matcher so it can begin matching new routes again.
matcher.resetMatcher();
reactRouter._internalSetRoutes(initReactRoutes);
}

function subscribe(listener: () => void) {
listeners = [listener];
return () => {
listeners = [];
};
}

function removeRoute(name: string) {
const matched = matcher.getRecordMatcher(name);
if (!matched) return;
Expand All @@ -320,10 +310,8 @@ export function createRouter({ beforeEach, initRoutes, mode, opt, getReactRoutes
removeRoute,
getRouteMetaByKey,
forwardRef,
subscribe,
initReady,
getRoutes,
getSnapshot,
resetRoute,
addReactRoutes,
push,
Expand Down
4 changes: 2 additions & 2 deletions packages/simple-router/src/types/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ export type BeforeEach = (
blockerOrJump: NavigationGuardNext
) => boolean;

export type Init = (currentFullPath: string, blockerOrJump: NavigationGuardNext) => Promise<boolean>;

export type AfterEach = (to: RouteLocationNormalizedLoaded, from: RouteLocationNormalizedLoaded) => void;

export type HistoryStateArray = Array<HistoryStateValue>;
Expand Down Expand Up @@ -121,3 +119,5 @@ export interface RouteQueryAndHash {
* @internal
*/
export interface RouteLocationNamedRaw extends RouteQueryAndHash, LocationAsRelativeRaw, RouteLocationOptions {}

export type Init = (currentFullPath: string) => Promise<RouteLocationNamedRaw | null>;
4 changes: 4 additions & 0 deletions packages/simple-router/src/utils/auxi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export function removeElement(arr: RouteObject[], name: string | undefined) {
return arr;
}

export function transformLocationToFullPath(location: Location) {
return location.pathname + location.search + location.hash;
}

export function transformLocationToRoute(
location: Location,
match: AgnosticDataRouteMatch[]
Expand Down
6 changes: 0 additions & 6 deletions src/hooks/common/route.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/hooks/common/routerPush.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRouter } from '@sa/simple-router';
import { useRoute, useRouter } from '@sa/simple-router';
import type { RouteKey } from '@elegant-router/types';
import type { RouteLocationNamedRaw } from '@sa/simple-router';

Expand Down
1 change: 1 addition & 0 deletions src/layouts/base-layout/MenuProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { FC, ReactNode } from 'react';
import { useMemo } from 'react';
import { useRoute } from '@sa/simple-router';
import { getSortRoutes } from '@/store/slice/route';
import { selectActiveFirstLevelMenuKey, setActiveFirstLevelMenuKey } from '@/store/slice/tab';
import { getActiveFirstLevelMenuKey } from '@/store/slice/tab/shared';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Button, Dropdown } from 'antd';
import type { MenuProps } from 'antd';
import { useSubmit } from 'react-router-dom';
import { useRoute } from '@sa/simple-router';
import { selectToken, selectUserInfo } from '@/store/slice/auth';

const UserAvatar = memo(() => {
Expand Down
1 change: 1 addition & 0 deletions src/layouts/modules/global-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ClassNames from 'classnames';
import type BScroll from '@better-scroll/core';
import { PageTab } from '@sa/materials';
import { useUpdateEffect } from 'ahooks';
import { useRoute } from '@sa/simple-router';
import DarkModeContainer from '@/components/stateless/common/DarkModeContainer';
import BetterScroll from '@/components/stateless/custom/BetterScroll';
import { getDarkMode, getThemeSettings } from '@/store/slice/theme';
Expand Down
11 changes: 8 additions & 3 deletions src/router/guard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,27 @@ import { getRouteHome, initAuthRoute, initConstantRoute } from '@/store/slice/ro
import { getRouteName, getRoutePath } from '@/router/elegant/transform';
import { isStaticSuper, selectUserInfo } from '@/store/slice/auth';

export const init: Init = async (currentFullPath, blockerOrJump) => {
export const init: Init = async currentFullPath => {
await store.dispatch(initConstantRoute());

const isLogin = Boolean(localStg.get('token'));

if (!isLogin) {
const loginRoute: RouteKey = 'login';
const routeHome = getRouteHome(store.getState());

const query = getRouteQueryOfLoginRoute(currentFullPath, routeHome as RouteKey);

const location: RouteLocationNamedRaw = {
name: loginRoute,
query
};

return blockerOrJump(location);
return location;
}
await store.dispatch(initAuthRoute());
return blockerOrJump();

return null;
};

/**
Expand Down Expand Up @@ -111,6 +115,7 @@ export const createRouteGuard: BeforeEach = (to, _, blockerOrJump) => {
];

// Find the first matching condition and execute its action

const executeRouteSwitch = routeSwitches.find(({ condition }) => condition)?.callback || blockerOrJump;

return executeRouteSwitch();
Expand Down
1 change: 0 additions & 1 deletion src/types/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ declare global {
const useResetState: typeof import('ahooks')['useResetState']
const useResolvedPath: typeof import('react-router-dom')['useResolvedPath']
const useResponsive: typeof import('ahooks')['useResponsive']
const useRoute: typeof import('../hooks/common/route')['useRoute']
const useRouterPush: typeof import('../hooks/common/routerPush')['useRouterPush']
const useRoutes: typeof import('react-router-dom')['useRoutes']
const useSafeState: typeof import('ahooks')['useSafeState']
Expand Down

0 comments on commit 6cf09f9

Please sign in to comment.