From 1f0dbaa1803ac728b6839694606fc0d477decc0b Mon Sep 17 00:00:00 2001 From: huangxuan Date: Fri, 1 Dec 2023 15:43:36 +0800 Subject: [PATCH] =?UTF-8?q?inula-router=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=8F=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/connect-router/connectedRouter.tsx | 9 +++++-- .../inula-router/src/history/hashHistory.ts | 4 +-- packages/inula-router/src/history/utils.ts | 14 +++++----- packages/inula-router/src/router/NavLink.tsx | 27 ++++++++++++++----- packages/inula-router/src/router/Route.tsx | 10 ++++--- packages/inula-router/src/router/Router.tsx | 16 +++++++---- .../inula-router/src/router/matcher/parser.ts | 2 +- .../inula-router/src/router/withRouter.tsx | 3 ++- 8 files changed, 58 insertions(+), 27 deletions(-) diff --git a/packages/inula-router/src/connect-router/connectedRouter.tsx b/packages/inula-router/src/connect-router/connectedRouter.tsx index a526663a..8ce5a383 100644 --- a/packages/inula-router/src/connect-router/connectedRouter.tsx +++ b/packages/inula-router/src/connect-router/connectedRouter.tsx @@ -16,7 +16,7 @@ import Inula from 'openinula'; import { useLayoutEffect, useRef, reduxAdapter, InulaNode } from 'openinula'; import { connect, ReactReduxContext } from 'react-redux'; -import { Store } from 'redux'; +import type { Store } from 'redux'; import { History, Location, Router } from '../router'; import { Action, DefaultStateType, Navigation } from '../history/types'; import { ActionMessage, onLocationChanged } from './actions'; @@ -130,9 +130,14 @@ function getConnectedRouter(type: StoreType) { ); }; + const ConnectedHRouterWithContext = (props: any) => { + const { store, ...rest } = props; + return ; + }; + // 针对不同的Store类型,使用对应的connect函数 if (type === 'InulaXCompat') { - return hConnect(null as any, mapDispatchToProps)(ConnectedRouterWithContext as any); + return hConnect(null as any, mapDispatchToProps)(ConnectedHRouterWithContext as any); } if (type === 'Redux') { return connect(null, mapDispatchToProps)(ConnectedRouterWithContext); diff --git a/packages/inula-router/src/history/hashHistory.ts b/packages/inula-router/src/history/hashHistory.ts index c44a85bb..f1cf421d 100644 --- a/packages/inula-router/src/history/hashHistory.ts +++ b/packages/inula-router/src/history/hashHistory.ts @@ -107,7 +107,7 @@ export function createHashHistory(option: HashHistoryOptio warning(state !== undefined, 'Hash history does not support state, it will be ignored'); const action = Action.push; - const location = createLocation(history.location, to, undefined, ''); + const location = createLocation(history.location, to, state, ''); transitionManager.confirmJumpTo(location, action, getUserConfirmation, isJump => { if (!isJump) { @@ -132,7 +132,7 @@ export function createHashHistory(option: HashHistoryOptio function replace(to: To, state?: S) { warning(state !== undefined, 'Hash history does not support state, it will be ignored'); const action = Action.replace; - const location = createLocation(history.location, to, undefined, ''); + const location = createLocation(history.location, to, state, ''); transitionManager.confirmJumpTo(location, action, getUserConfirmation, isJump => { if (!isJump) { diff --git a/packages/inula-router/src/history/utils.ts b/packages/inula-router/src/history/utils.ts index 27447967..8a671372 100644 --- a/packages/inula-router/src/history/utils.ts +++ b/packages/inula-router/src/history/utils.ts @@ -28,8 +28,8 @@ export function createPath(path: Partial): string { } export function parsePath(url: string): Partial { + let pathname = url || '/'; const parsedPath: Partial = { - pathname: url || '/', search: '', hash: '', }; @@ -38,16 +38,16 @@ export function parsePath(url: string): Partial { if (hashIdx > -1) { const hash = url.substring(hashIdx); parsedPath.hash = hash === '#' ? '' : hash; - url = url.substring(0, hashIdx); + pathname = pathname.substring(0, hashIdx); } const searchIdx = url.indexOf('?'); if (searchIdx > -1) { const search = url.substring(searchIdx); parsedPath.search = search === '?' ? '' : search; - url = url.substring(0, searchIdx); + pathname = pathname.substring(0, searchIdx); } - parsedPath.pathname = url; + parsedPath.pathname = pathname; return parsedPath; } @@ -116,12 +116,12 @@ export function stripBasename(path: string, prefix: string): string { export function createMemoryRecord(initVal: S, fn: (arg: S) => T) { let visitedRecord: T[] = [fn(initVal)]; - function getDelta(to: S, form: S): number { - let toIdx = visitedRecord.lastIndexOf(fn(to)); + function getDelta(toKey: S, formKey: S): number { + let toIdx = visitedRecord.lastIndexOf(fn(toKey)); if (toIdx === -1) { toIdx = 0; } - let fromIdx = visitedRecord.lastIndexOf(fn(form)); + let fromIdx = visitedRecord.lastIndexOf(fn(formKey)); if (fromIdx === -1) { fromIdx = 0; } diff --git a/packages/inula-router/src/router/NavLink.tsx b/packages/inula-router/src/router/NavLink.tsx index 37cbbeca..9a836e71 100644 --- a/packages/inula-router/src/router/NavLink.tsx +++ b/packages/inula-router/src/router/NavLink.tsx @@ -24,27 +24,42 @@ import { parsePath } from '../history/utils'; type NavLinkProps = { to: Partial | string | ((location: Location) => string | Partial); - isActive?: (match: Matched | null, location: Location) => boolean; + isActive?

(match: Matched

| null, location: Location): boolean; + exact?: boolean; + strict?: boolean; + sensitive?: boolean; + className?: string | ((isActive: boolean) => string); + activeClassName?: string; [key: string]: any; -} & LinkProps; +} & Omit; type Page = 'page'; function NavLink

(props: P) { - const { to, isActive, ...rest } = props; + const { to, isActive, exact, strict, sensitive, className, activeClassName, ...rest } = props; const context = useContext(Context); const toLocation = typeof to === 'function' ? to(context.location) : to; const { pathname } = typeof toLocation === 'string' ? parsePath(toLocation) : toLocation; - const match = pathname ? matchPath(context.location.pathname, pathname) : null; + const match = pathname ? matchPath(context.location.pathname, pathname, { + exact: exact, + strictMode: strict, + caseSensitive: sensitive, + }) : null; - const isLinkActive = match && isActive ? isActive(match, context.location) : false; + const isLinkActive = !!(isActive ? isActive(match, context.location) : match); + + let classNames = typeof className === 'function' ? className(isLinkActive) : className; + if (isLinkActive) { + classNames = [activeClassName, classNames].filter(Boolean).join(''); + } const page: Page = 'page'; const otherProps = { - 'aria-current': isLinkActive ? page : false, + className: classNames, + 'aria-current': isLinkActive ? page : undefined, ...rest, }; diff --git a/packages/inula-router/src/router/Route.tsx b/packages/inula-router/src/router/Route.tsx index fdf2db7f..ddd7c195 100644 --- a/packages/inula-router/src/router/Route.tsx +++ b/packages/inula-router/src/router/Route.tsx @@ -43,15 +43,19 @@ export type RouteProps

= {}, Path extends string = function Route = GetURLParams>(props: RouteProps) { const context = useContext(RouterContext); - const { computed, location, path } = props; - let { children, component, render } = props; + const { computed, location, path, component, render, strict, sensitive, exact } = props; + let { children } = props; let match: Matched

| null; const routeLocation = location || context.location; if (computed) { match = computed; } else if (path) { - match = matchPath

(routeLocation.pathname, path); + match = matchPath

(routeLocation.pathname, path, { + strictMode: strict, + caseSensitive: sensitive, + exact: exact, + }); } else { match = context.match; } diff --git a/packages/inula-router/src/router/Router.tsx b/packages/inula-router/src/router/Router.tsx index dd9791a1..1dcdf7e6 100644 --- a/packages/inula-router/src/router/Router.tsx +++ b/packages/inula-router/src/router/Router.tsx @@ -29,22 +29,27 @@ function Router

(props: P) { const { history, children = null } = props; const [location, setLocation] = useState(props.history.location); const pendingLocation = useRef(null); + const unListen = useRef void)>(null); + const isMount = useRef(false); // 在Router加载时就监听history地址变化,以保证在始渲染时重定向能正确触发 - const unListen = useRef void)>( - history.listen(arg => { + if (unListen.current === null) { + unListen.current = history.listen(arg => { pendingLocation.current = arg.location; - }), - ); + }); + } // 模拟componentDidMount和componentWillUnmount useLayoutEffect(() => { + isMount.current = true; if (unListen.current) { unListen.current(); } // 监听history中的位置变化 unListen.current = history.listen(arg => { - setLocation(arg.location); + if (isMount.current) { + setLocation(arg.location); + } }); if (pendingLocation.current) { @@ -53,6 +58,7 @@ function Router

(props: P) { return () => { if (unListen.current) { + isMount.current = false; unListen.current(); unListen.current = null; pendingLocation.current = null; diff --git a/packages/inula-router/src/router/matcher/parser.ts b/packages/inula-router/src/router/matcher/parser.ts index 0598066c..ea75e4e5 100644 --- a/packages/inula-router/src/router/matcher/parser.ts +++ b/packages/inula-router/src/router/matcher/parser.ts @@ -40,7 +40,7 @@ export type Matched

= { const defaultOption: Required = { // url匹配时是否大小写敏感 - caseSensitive: true, + caseSensitive: false, // 是否严格匹配url结尾的/ strictMode: false, // 是否完全精确匹配 diff --git a/packages/inula-router/src/router/withRouter.tsx b/packages/inula-router/src/router/withRouter.tsx index 3d7f58bd..04c588c8 100644 --- a/packages/inula-router/src/router/withRouter.tsx +++ b/packages/inula-router/src/router/withRouter.tsx @@ -20,10 +20,11 @@ import RouterContext from './context'; function withRouter(Component: C) { function ComponentWithRouterProp(props: any) { + const { wrappedComponentRef, ...rest } = props; const { history, location, match } = useContext(RouterContext); const routeProps = { history: history, location: location, match: match }; - return ; + return ; } return ComponentWithRouterProp;