React Native 版 react-router-dom:基于 React Navigation 的配置式路由(Stack/Tabs/Outlet/Guard + Web linking)
在 React Native 上提供一套尽量贴近 react-router-dom 的路由心智:用 URL(pathname/search/hash)描述当前页面,用配置式 routes 定义路由树,并在 RN 端映射到 React Navigation(Stack/Tabs),同时兼容 react-native-web 的地址栏直达、刷新、回退。
- 配置式路由:用 RouteProps[] 描述路由树
- 统一跳转心智:navigate('/settings/detail') 可跨 Tabs/嵌套栈直达目标页面
- 嵌套路由:
- Guard:全局 beforeEach + 路由级 guard
- Web linking:支持 react-native-web URL 同步(直达/刷新/回退)
``bash`
npm i react-native-router-dom
本库已内置 React Navigation 核心依赖(v7),你无需单独安装。
但你需要手动安装以下原生依赖(React Navigation 运行必需):
`bash`
npm i react-native-screens react-native-safe-area-context
> ⚠️ 注意:安装完成后,iOS 项目请务必执行 cd ios && pod install。
`ts
import type { RouteProps } from 'react-native-router-dom';
import { Login } from './Login';
import { Home } from './Home';
export const routes: RouteProps[] = [
{ path: '/login', element: Login, options: { headerShown: false } },
{ path: '/home', element: Home, options: { title: '首页' } },
];
`
`tsx
import React from 'react';
import { RouterProvider, createNativeRouter } from 'react-native-router-dom';
import { routes } from './routes';
export default function App() {
const router = React.useMemo(() => createNativeRouter(routes), []);
return
}
`
RouteProps 是你唯一需要维护的路由“真相来源”。它会被映射成 React Navigation 的一棵 Navigator 树。
类型:
`ts
type RouteType = 'stack' | 'tabs';
type RouteMeta = Record
type RouteElement = React.ComponentType
type RouteProps = {
path?: string;
index?: boolean;
element?: RouteElement;
children?: RouteProps[];
type?: RouteType;
navigatorOptions?: any;
options?: any;
meta?: RouteMeta;
guard?: RouteGuard;
};
`
关键字段:
- path:
- 绝对 path:以 / 开头,例如 /settings/detail
- 相对 path:不以 / 开头,例如 detail,会拼接到父路由 path 后
- 通配:/docs/*(匹配任意后续片段)
- 动态参数:/user/:id
- index:对齐 react-router 的 index route(匹配父路由的 path;此时 path 可省略)
- element:页面组件(ComponentType / ReactElement / null)
- children:嵌套路由
- type:
- 'tabs':该节点的 children 会被渲染为 Tab.Navigator
- 'stack'(默认):该节点的 children 会被渲染为 Stack.Navigator
- meta:任意元信息(常用于 Guard)
- guard:路由级守卫(从父到子依次执行)
- navigatorOptions:React Navigation Navigator 级 props(原样透传到 Tab.Navigator / Stack.Navigator)
- options:React Navigation Screen options(原样透传到 Tab.Screen / Stack.Screen)
重要约束:
- leaf route(没有 children 的路由)必须有 element,否则会在启动时抛错
- 每个非 index route 必须提供 path;否则会抛错:Route 缺少 path(或未标记 index: true)
- leaf route 必须有 element;否则会抛错:Route "/xxx" 缺少 element(leaf route 必须可渲染)
- index route 的“路由语义 path”会等于父路由的 path(用于匹配/生成 URL)
- Tabs 的初始页面选择规则:优先选择第一个非 index 子路由
- Stack 的初始页面选择规则:优先选择第一个 index 子路由
- 内部会为每个 route 生成全局唯一的 screenName;当配置导致 screenName 冲突时会抛错:重复的 screenName
为了避免“改一个 TabBar 样式就要改源码发包”,本库将 React Navigation 的参数分成两层透传:
- Navigator 级:用 navigatorOptions,会原样透传到 Tab.Navigator / Stack.Navigatoroptions
- Screen 级:用 ,会原样透传到 Tab.Screen / Stack.Screen
示例:调整 TabBar 图标/文字布局方向(官方 screenOptions)
`tsx
import { Image } from 'react-native';
import type { RouteProps } from 'react-native-router-dom';
const Home = () => null;
export const routes: RouteProps[] = [
{
path: '/main',
type: 'tabs',
navigatorOptions: {
screenOptions: {
tabBarLabelPosition: 'beside-icon',
tabBarItemStyle: { flexDirection: 'row' },
},
},
children: [
{
path: '/home',
element: Home,
options: {
title: '首页',
tabBarLabel: '首页',
tabBarIcon: ({ focused, size }) => (
style={{ width: size, height: size }}
resizeMode="contain"
/>
),
},
},
],
},
];
`
useLocation() 会返回当前的 RouteLocation:
- pathname:/settings/detail
- search:?x=1
- hash:#top
- params:动态参数与通配参数(:id、*)
- matches:从父到子匹配到的 route 列表(可用于 Guard 判定)
`ts
import { useNavigate } from 'react-native-router-dom';
const navigate = useNavigate();
await navigate('/profile'); // 绝对跳转
await navigate('/user/42?x=1#top'); // search/hash 也会透传
await navigate(-1); // 返回
`
本库直接复用 React Navigation 的动画能力。你不需要学习新的 API,只需要将 React Navigation 的配置写在 options 或 navigatorOptions 里即可。
#### 1. 单个页面配置动画
在 RouteProps 中使用 options 字段,这相当于 。
`ts`
{
path: '/login',
element: Login,
options: {
// 设为模态窗效果(从下往上弹出)
presentation: 'modal',
// 简单的淡入淡出
animation: 'fade',
},
}
#### 2. 全局/Stack 级配置动画
在 RouteProps 中使用 navigatorOptions 字段,这相当于 。
`ts`
{
path: '/', // 根路由通常是 stack
navigatorOptions: {
screenOptions: {
// 让该 stack 下所有页面默认都是 slide_from_right
animation: 'slide_from_right',
// 统一配置头部样式
headerStyle: { backgroundColor: 'white' },
},
},
children: [
// ... 子路由都会继承这个动画配置
]
}
#### 3. 常用动画预设(Native Stack)
React Navigation 提供了丰富的预设动画(animation 属性):
- 'default': 平台默认动画(iOS 右侧滑入,Android 底部浮现或淡入)'fade'
- : 淡入淡出'slide_from_right'
- : 从右侧滑入(类似 iOS 默认)'slide_from_bottom'
- : 从底部滑入(类似 Android 默认)'simple_push'
- : 标准 push 动画
> 更多高级配置(如 transitionSpec)请参考 React Navigation 文档。
相对跳转说明:
- navigate('detail') 会基于“当前 committed location.pathname”做相对解析
- committed location 由
- 如果你在 RouterProvider ready 之前调用,可能会以 '/' 作为基准
`ts
import { useRouter } from 'react-native-router-dom';
const router = useRouter();
await router.push('/home');
await router.replace('/login');
router.back();
`
`ts
import { generatePath } from 'react-native-router-dom';
generatePath('/user/:id', { id: '42' }); // /user/42
generatePath('/docs/', { '': 'a/b' }); // /docs/a/b
`
RouterProvider 是整个路由系统的宿主,负责:
- 持有 router 实例并通过 Context 暴露给 Hooks/Link/Navigate
- 将 RouteProps[] 映射成 React Navigation 的 Navigator 树
- 处理 onStateChange,运行 Guard,并维护当前 committed location
- 在 Web 端连接 React Navigation linking 与浏览器地址栏
类型:
`ts
import type { RouterProviderProps } from 'react-native-router-dom';
type RouterProviderProps = {
/* 已创建好的 Router;与 routes 互斥,优先使用该值 /
router?: NativeRouter;
/* 路由配置;不传 router 时必传 /
routes?: RouteProps[];
/* 全局守卫(等价于 createNativeRouter(..., { beforeEach })) /
beforeEach?: RouteGuard;
/* 自定义 React Navigation linking;不传时会自动基于 routes 生成 /
linking?: any;
/* linking 前缀,仅在 linking 未传时生效,例如 ['https://example.com'] /
prefixes?: string[];
/**
* Web 路由模式(只在 linking 未传时生效)
* - 'history': HTML5 History(默认)
* - 'hash': Hash 模式(#/path)
*/
linkingType?: 'history' | 'hash';
};
`
用法示例:直接传 routes(简单场景推荐):
`tsx
import { RouterProvider } from 'react-native-router-dom';
import { routes } from './routes';
export default function App() {
return
}
`
用法示例:显式创建 router(方便做 SSR 或测试):
`tsx
import React from 'react';
import { RouterProvider, createNativeRouter } from 'react-native-router-dom';
import { routes } from './routes';
export default function App() {
const router = React.useMemo(() => createNativeRouter(routes, { beforeEach }), []);
return
}
`
- 父路由 element 中渲染
-
类型:
`ts`
type OutletProps = {
/* 传给子路由的上下文数据,useOutletContext
context?: unknown;
};
用法示例:布局向子页面透传数据:
`tsx
import { Outlet, useOutletContext } from 'react-native-router-dom';
function SettingsLayout() {
const user = { name: 'Alice' };
return
}
function SettingsDetail() {
const user = useOutletContext<{ name: string }>();
return
}
`
`tsx
import { Link, NavLink } from 'react-native-router-dom';
去设置
{({ isActive }) => (isActive ? '当前页' : '去首页')}
`
LinkProps:
`ts
import type { PressableProps } from 'react-native';
type LinkProps = Omit
/* 目标路径,支持绝对/相对、search、hash 等 /
to: string;
/* 是否使用 replace 语义(默认 push) /
replace?: boolean;
/* 额外透传给导航参数(会进入 React Navigation route.params) /
params?: Record
/* 渲染内容,通常是 Text 或 View /
children?: React.ReactNode;
};
`
NavLinkProps:
`ts`
type NavLinkProps = Omit
/* 是否使用“完全匹配”模式(类似 react-router 的 end) /
end?: boolean;
/* 支持函数 children,便于按 active 状态定制样式 /
children?: React.ReactNode | ((args: { isActive: boolean }) => React.ReactNode);
/* 支持函数 style,便于按 active 状态定制样式 /
style?: StyleProp
};
NavLink style 函数示例:
`tsx`
style={({ isActive }) => ({
backgroundColor: isActive ? '#e0e0e0' : 'transparent',
padding: 12,
borderRadius: 8,
})}
>
NavLink 的 isActive 规则:
- end=true:仅当 current === target 时 active
- end=false(默认):current === target 或 current 以 ${target}/ 开头时 active
- target 为相对路径时,会基于当前 pathname 解析后再判断
`tsx
import { Navigate } from 'react-native-router-dom';
export function Jump() {
return
}
`
类型:
`ts`
type NavigateProps = {
/* 目标路径,支持绝对/相对、search、hash 等 /
to: string;
/* 是否 replace 当前历史记录(默认 false,即 push) /
replace?: boolean;
/* 透传给目标页面的 params(React Navigation route.params) /
params?: Record
};
Navigate 本质上是一个副作用组件:
- 渲染时立即调用 useNavigate() 触发跳转,并返回 null
- 常用于 routes 配置里作为 element,或某些中转页面
`ts`
const router = useNativeRouter();
- 只能在
- 返回 NativeRouter 实例,包含:
- routes:当前 RouteProps[]
- navigationRef:React Navigation 的 NavigationContainerRef
- beforeEach(fn):注册全局守卫,返回取消函数
- navigate(to, options?) / push(to, params?) / replace(to, params?) / back()
- getCurrentLocation()
适合做一些底层集成场景,例如自定义返回行为等。
`ts`
const { push, replace, back, navigate } = useRouter();
- 是对 useNativeRouter 的“瘦包装”,只暴露最常用的导航方法
- 适用于大多数业务组件
`ts
const navigate = useNavigate();
await navigate('/profile');
await navigate(-1); // 返回
await navigate('/user/42?x=1#top', { replace: true, params: { from: 'home' } });
`
签名:
`ts
type NavigateFn = (to: string | number, options?: NavigateOptions) => Promise
type NavigateOptions = {
replace?: boolean;
params?: Record
};
`
- to 为 number 且 < 0 时等价于 back()
- 返回 Promise
`ts`
const location = useLocation();
// location: RouteLocation | null
RouteLocation 结构:
`ts`
type RouteLocation = {
pathname: string;
search: string;
hash: string;
params: Record
matches: RouteMatch[];
};
RouteMatch:
`ts`
type RouteMatch = {
route: RouteProps;
pathname: string;
params: Record
};
`ts`
const params = useParams(); // Record
const id = params.id;
const rest = params['']; // 对应通配符 /docs/
- 来源于当前匹配到的 leaf route 的动态参数与通配符参数
`ts
const [searchParams, setSearchParams] = useSearchParams({ page: '1' });
const page = searchParams.get('page'); // string | null
setSearchParams({ page: '2' }); // ?page=2
setSearchParams('page=3&sort=desc', { replace: true });
`
签名:
`ts
function useSearchParams(
defaultInit?: string | Record
): [
SearchParamsLike,
(nextInit: string | Record
];
type SearchParamsLike = {
get: (name: string) => string | null;
has: (name: string) => boolean;
set: (name: string, value: string) => void;
delete: (name: string) => void;
entries: () => IterableIterator<[string, string]>;
toString: () => string;
};
`
- 返回的 SearchParamsLike 在有 URLSearchParams 的环境(Web)中直接使用原生实现,在 Hermes 等没有 URLSearchParams 的环境中自动降级为内置的轻量实现
- defaultInit 仅在当前 search 没有某个 key 时作为默认值写入
- setSearchParams 会基于当前 pathname/hash 生成新 URL,并通过 navigate 跳转
`ts`
const match = useMatch('/settings/*');
// match: { pathname, params, pattern } | null
- pattern 支持动态参数与通配符,语义与 RouteProps.path 一致
- 典型用途:根据某个子路由是否匹配来高亮菜单等
`ts
import { useBlocker } from 'react-native-router-dom';
// 布尔值形式:有未保存内容时阻止离开
useBlocker(hasUnsavedChanges);
// 函数形式:根据目标路由决定是否阻止
useBlocker(({ to }) => to.pathname !== '/save-confirm' && hasUnsavedChanges);
`
签名:
`ts
type BlockerFunction = (ctx: RouteGuardContext) => boolean;
function useBlocker(blocker: BlockerFunction | boolean): void;
`
- 返回 true 表示阻止导航,false 表示放行beforeEach
- 内部通过 实现,组件卸载时自动取消注册
- 典型场景:表单编辑页、文档编辑页等需要防止意外离开的页面
`ts`
const ctx = useOutletContext<{ name: string }>();
- 获取父级 Outlet 通过 context 传下来的数据
Guard 支持两层:
1) 全局:router.beforeEach(fn) 或 createNativeRouter(routes, { beforeEach: fn })
2) 路由级:route.guard
执行顺序:
- 先执行所有 beforeEach(按注册顺序)
- 再从父到子依次执行 matches 中每个 route.guard
返回值语义:
- true / void:放行
- false:拦截(停留在原页面;Tab 点击会被阻止并回滚)
- string:重定向到该 path(默认 replace)
- redirect(to, { replace? }):更显式的重定向对象
类型:
`ts
type RouteGuardContext = {
to: RouteLocation;
from: RouteLocation | null;
};
type RouteGuardResult = boolean | Redirect | string | void;
type RouteGuard = (
ctx: RouteGuardContext,
) => RouteGuardResult | Promise
`
示例:
`ts
import { redirect } from 'react-native-router-dom';
router.beforeEach(({ to }) => {
const requiresAuth = to.matches.some(m => (m.route.meta as any)?.requiresAuth);
if (!requiresAuth) return true;
return redirect('/login');
});
`
示例:注册/取消注册 beforeEach
`ts
const dispose = router.beforeEach(async ({ to }) => {
if (to.pathname === '/login') return true;
return true;
});
dispose();
`
示例:路由级 guard(只对该分支生效)
`ts
import { redirect, type RouteProps } from 'react-native-router-dom';
export const routes: RouteProps[] = [
{
path: '/guarded',
element: GuardedPage,
guard: async ({ to }) => {
if (await isLoggedIn()) return true;
return redirect('/login', { replace: true });
},
},
];
`
RouterProvider 在 web 上会通过 React Navigation linking 与地址栏同步:
- history 模式(默认):
- 支持地址栏直达:直接访问 /settings/detail
- 支持刷新:刷新后仍停留在对应页面
- 支持回退:浏览器 back/forward 与导航状态同步
- 要求 dev server 开启 history fallback(例如 webpack-dev-server 的 historyApiFallback: true)
- hash 模式:
- URL 形如 http://localhost:8080/#/settings/detail
- 不依赖 history fallback(因为路径在 hash 里)
- 通过 RouterProvider 内部同步地址栏,避免 React Navigation 在 web 下重复拼接 hash
要点:
- 如果你需要自定义 scheme/prefix,可以用 createLinking(routes, { prefixes }) 并传给 RouterProvider 的 linking
- 如果你需要 hash 模式:
目录:demo/
运行:
`bash
cd demo
npm i
demo 覆盖的验证路由(建议在 web 下逐个用地址栏直达 + 刷新验证):
- /home:Link/NavLink、useRouter、generatePath、跨 Tab/嵌套跳转
- /settings:Outlet + index route、useMatch、useOutletContext、useSearchParams
- /settings/detail:相对跳转(..)、navigate(-1)、Guard(需要登录)
- /params:useLocation/useSearchParams 示例
- /user/:id:useParams 动态参数
- /docs/:useParams()[''] 通配
- /guarded:route.guard 示例
- /jump: 示例(带 query/hash)
导出 API(总览)
$3
`ts
import { createNativeRouter } from 'react-native-router-dom';const router = createNativeRouter(routes, {
beforeEach: async ({ to, from }) => {
// 可做登录校验、埋点等
return true;
},
});
`签名:
`ts
type CreateNativeRouterOptions = {
beforeEach?: RouteGuard;
};function createNativeRouter(
routes: RouteProps[],
options?: CreateNativeRouterOptions,
): NativeRouter;
`NativeRouter 关键字段:
- routes: RouteProps[]
- navigationRef: NavigationContainerRefWithCurrent
- beforeEach(guard: RouteGuard): () => void
- navigate(to: string | number, options?: NavigateOptions): Promise
- push(to: string, params?: Record): Promise
- replace(to: string, params?: Record): Promise
- back(): void
- getCurrentLocation(): RouteLocation | null
> 一般业务只需要通过 RouterProvider + Hooks/Link 使用;直接操作 NativeRouter 适合做底层集成。
$3
`ts
import { createLinking } from 'react-native-router-dom';const linking = createLinking(routes, {
prefixes: ['https://example.com', 'myapp://'],
});
;
`签名:
`ts
type LinkingOptions = {
prefixes?: string[];
};function createLinking(routes: RouteProps[], options?: LinkingOptions): {
prefixes: string[];
config: { screens: Record };
};
`- 默认 prefixes 为 [''],即可直接用 /path 形式的 URL
- config.screens 结构与 React Navigation linking config 一致
$3
`ts
import { redirect, isRedirect } from 'react-native-router-dom';router.beforeEach(({ to }) => {
if (to.pathname.startsWith('/admin') && !isAdmin()) {
return redirect('/login', { replace: true });
}
});
`签名:
`ts
type Redirect = {
type: 'redirect';
to: string;
replace?: boolean;
};function redirect(to: string, options?: { replace?: boolean }): Redirect;
function isRedirect(value: unknown): value is Redirect;
`$3
`ts
import { generatePath } from 'react-native-router-dom';const url = generatePath('/user/:id', { id: user.id });
// /user/123
`签名:
`ts
function generatePath(pattern: string, params?: Record): string;
`- pattern 支持 :id、:slug 和 * 通配符
$3
常用类型:
- RouteProps:路由配置
- RouteType:'stack' | 'tabs'
- RouteMeta:Record
- RouteGuard / RouteGuardContext / RouteGuardResult
- Redirect
- RouteLocation / RouteMatch
- SearchParamsLike:useSearchParams 返回的搜索参数对象类型
- BlockerFunction:useBlocker 的回调函数类型
所有类型均从包入口导出,可直接:
`ts
import type {
RouteProps,
RouteLocation,
RouteMatch,
RouteGuard,
RouteGuardContext,
} from 'react-native-router-dom';
``在业务项目中,推荐尽量使用这些类型而不是自己手写结构,以便在库升级时获得更好的类型兼容性。