npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-router-dom

v0.0.5

Published

React Native 版 react-router-dom:基于 React Navigation 的配置式路由(Stack/Tabs/Outlet/Guard + Web linking)

Readme

react-native-router-dom

在 React Native 上提供一套尽量贴近 react-router-dom 的路由心智:用 URL(pathname/search/hash)描述当前页面,用配置式 routes 定义路由树,并在 RN 端映射到 React Navigation(Stack/Tabs),同时兼容 react-native-web 的地址栏直达、刷新、回退。

核心特性

  • 配置式路由:用 RouteProps[] 描述路由树
  • 统一跳转心智:navigate('/settings/detail') 可跨 Tabs/嵌套栈直达目标页面
  • 嵌套路由: + index route
  • Guard:全局 beforeEach + 路由级 guard
  • Web linking:支持 react-native-web URL 同步(直达/刷新/回退)

安装

npm i react-native-router-dom

依赖说明

本库已内置 React Navigation 核心依赖(v7),你无需单独安装。

但你需要手动安装以下原生依赖(React Navigation 运行必需):

npm i react-native-screens react-native-safe-area-context

⚠️ 注意:安装完成后,iOS 项目请务必执行 cd ios && pod install

快速开始

1) 定义路由(routes)

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: '首页' } },
];

2) 渲染 RouterProvider

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 <RouterProvider router={router} />;
}

核心概念(强烈建议先看)

RouteProps(路由配置)

RouteProps 是你唯一需要维护的路由“真相来源”。它会被映射成 React Navigation 的一棵 Navigator 树。

类型:

type RouteType = 'stack' | 'tabs';

type RouteMeta = Record<string, unknown>;

type RouteElement = React.ComponentType<any> | React.ReactElement | null;

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

Tabs/Stack 的 React Navigation 参数透传(与官方 API 对齐)

为了避免“改一个 TabBar 样式就要改源码发包”,本库将 React Navigation 的参数分成两层透传:

  • Navigator 级:用 navigatorOptions,会原样透传到 Tab.Navigator / Stack.Navigator
  • Screen 级:用 options,会原样透传到 Tab.Screen / Stack.Screen

示例:调整 TabBar 图标/文字布局方向(官方 screenOptions)

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 }) => (
            <Image
              source={focused ? require('./home-active.png') : require('./home.png')}
              style={{ width: size, height: size }}
              resizeMode="contain"
            />
          ),
        },
      },
    ],
  },
];

location(当前路由状态)

useLocation() 会返回当前的 RouteLocation:

  • pathname:/settings/detail
  • search:?x=1
  • hash:#top
  • params:动态参数与通配参数(:id、*)
  • matches:从父到子匹配到的 route 列表(可用于 Guard 判定)

跳转与导航

useNavigate(推荐)

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 的配置写在 optionsnavigatorOptions 里即可。

1. 单个页面配置动画

RouteProps 中使用 options 字段,这相当于 <Stack.Screen options={...} />

{
  path: '/login',
  element: Login,
  options: {
    // 设为模态窗效果(从下往上弹出)
    presentation: 'modal',
    // 简单的淡入淡出
    animation: 'fade',
  },
}

2. 全局/Stack 级配置动画

RouteProps 中使用 navigatorOptions 字段,这相当于 <Stack.Navigator screenOptions={...} />

{
  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 之前调用,可能会以 '/' 作为基准

useRouter(push/replace/back 的别名集合)

import { useRouter } from 'react-native-router-dom';

const router = useRouter();
await router.push('/home');
await router.replace('/login');
router.back();

generatePath(动态参数生成)

import { generatePath } from 'react-native-router-dom';

generatePath('/user/:id', { id: '42' }); // /user/42
generatePath('/docs/*', { '*': 'a/b' }); // /docs/a/b

组件

RouterProvider

RouterProvider 是整个路由系统的宿主,负责:

  • 持有 router 实例并通过 Context 暴露给 Hooks/Link/Navigate
  • 将 RouteProps[] 映射成 React Navigation 的 Navigator 树
  • 处理 onStateChange,运行 Guard,并维护当前 committed location
  • 在 Web 端连接 React Navigation linking 与浏览器地址栏

类型:

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(简单场景推荐):

import { RouterProvider } from 'react-native-router-dom';
import { routes } from './routes';

export default function App() {
  return <RouterProvider routes={routes} />;
}

用法示例:显式创建 router(方便做 SSR 或测试):

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 <RouterProvider router={router} />;
}

Outlet(嵌套路由)

  • 父路由 element 中渲染 ,子路由页面会在 Outlet 位置渲染
  • + useOutletContext() 传递布局上下文

类型:

type OutletProps = {
  /** 传给子路由的上下文数据,useOutletContext<T>() 可获取 */
  context?: unknown;
};

用法示例:布局向子页面透传数据:

import { Outlet, useOutletContext } from 'react-native-router-dom';

function SettingsLayout() {
  const user = { name: 'Alice' };
  return <Outlet context={user} />;
}

function SettingsDetail() {
  const user = useOutletContext<{ name: string }>();
  return <Text>当前用户:{user.name}</Text>;
}

Link / NavLink

import { Link, NavLink } from 'react-native-router-dom';

<Link to="/settings">去设置</Link>

<NavLink to="/home">
  {({ isActive }) => (isActive ? '当前页' : '去首页')}
</NavLink>

LinkProps:

import type { PressableProps } from 'react-native';

type LinkProps = Omit<PressableProps, 'children'> & {
  /** 目标路径,支持绝对/相对、search、hash 等 */
  to: string;
  /** 是否使用 replace 语义(默认 push) */
  replace?: boolean;
  /** 额外透传给导航参数(会进入 React Navigation route.params) */
  params?: Record<string, any>;
  /** 渲染内容,通常是 Text 或 View */
  children?: React.ReactNode;
};

NavLinkProps:

type NavLinkProps = Omit<LinkProps, 'children'> & {
  /** 是否使用“完全匹配”模式(类似 react-router 的 end) */
  end?: boolean;
  /** 支持函数 children,便于按 active 状态定制样式 */
  children?: React.ReactNode | ((args: { isActive: boolean }) => React.ReactNode);
};

NavLink 的 isActive 规则:

  • end=true:仅当 current === target 时 active
  • end=false(默认):current === target 或 current 以 ${target}/ 开头时 active
  • target 为相对路径时,会基于当前 pathname 解析后再判断

Navigate(声明式跳转)

import { Navigate } from 'react-native-router-dom';

export function Jump() {
  return <Navigate to="/home" replace />;
}

类型:

type NavigateProps = {
  /** 目标路径,支持绝对/相对、search、hash 等 */
  to: string;
  /** 是否 replace 当前历史记录(默认 false,即 push) */
  replace?: boolean;
  /** 透传给目标页面的 params(React Navigation route.params) */
  params?: Record<string, any>;
};

Navigate 本质上是一个副作用组件:

  • 渲染时立即调用 useNavigate() 触发跳转,并返回 null
  • 常用于 routes 配置里作为 element,或某些中转页面

Hooks(API 参考)

useNativeRouter

const router = useNativeRouter();
  • 只能在 内使用,否则会抛错
  • 返回 NativeRouter 实例,包含:
    • routes:当前 RouteProps[]
    • navigationRef:React Navigation 的 NavigationContainerRef
    • beforeEach(fn):注册全局守卫,返回取消函数
    • navigate(to, options?) / push(to, params?) / replace(to, params?) / back()
    • getCurrentLocation()

适合做一些底层集成场景,例如自定义返回行为等。

useRouter

const { push, replace, back, navigate } = useRouter();
  • 是对 useNativeRouter 的“瘦包装”,只暴露最常用的导航方法
  • 适用于大多数业务组件

useNavigate

const navigate = useNavigate();

await navigate('/profile');
await navigate(-1); // 返回
await navigate('/user/42?x=1#top', { replace: true, params: { from: 'home' } });

签名:

type NavigateFn = (to: string | number, options?: NavigateOptions) => Promise<boolean>;

type NavigateOptions = {
  replace?: boolean;
  params?: Record<string, any>;
};
  • to 为 number 且 < 0 时等价于 back()
  • 返回 Promise,表示是否成功触发导航(未匹配到路由、NavigationContainer 未 ready 等情况会返回 false)

useLocation

const location = useLocation();
// location: RouteLocation | null

RouteLocation 结构:

type RouteLocation = {
  pathname: string;
  search: string;
  hash: string;
  params: Record<string, string>;
  matches: RouteMatch[];
};

RouteMatch:

type RouteMatch = {
  route: RouteProps;
  pathname: string;
  params: Record<string, string>;
};

useParams

const params = useParams(); // Record<string, string>
const id = params.id;
const rest = params['*']; // 对应通配符 /docs/*
  • 来源于当前匹配到的 leaf route 的动态参数与通配符参数

useSearchParams

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 });

签名:

function useSearchParams(
  defaultInit?: string | Record<string, string> | URLSearchParams,
): [
  URLSearchParams,
  (nextInit: string | Record<string, string> | URLSearchParams, options?: { replace?: boolean }) => void,
];
  • defaultInit 仅在当前 search 没有某个 key 时作为默认值写入
  • setSearchParams 会基于当前 pathname/hash 生成新 URL,并通过 navigate 跳转

useMatch

const match = useMatch('/settings/*');
// match: { pathname, params, pattern } | null
  • pattern 支持动态参数与通配符,语义与 RouteProps.path 一致
  • 典型用途:根据某个子路由是否匹配来高亮菜单等

useOutletContext

const ctx = useOutletContext<{ name: string }>();
  • 获取父级 Outlet 通过 context 传下来的数据

Guard(路由守卫)

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? }):更显式的重定向对象

类型:

type RouteGuardContext = {
  to: RouteLocation;
  from: RouteLocation | null;
};

type RouteGuardResult = boolean | Redirect | string | void;

type RouteGuard = (
  ctx: RouteGuardContext,
) => RouteGuardResult | Promise<RouteGuardResult>;

示例:

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

const dispose = router.beforeEach(async ({ to }) => {
  if (to.pathname === '/login') return true;
  return true;
});

dispose();

示例:路由级 guard(只对该分支生效)

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 });
    },
  },
];

Web linking(react-native-web)

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 模式:<RouterProvider linkingType="hash" ... />

Demo(建议作为“可运行文档”使用)

目录:demo/

运行:

cd demo
npm i

# iOS / Android
npm run ios
npm run android

# Web
npm run web

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(总览)

createNativeRouter

import { createNativeRouter } from 'react-native-router-dom';

const router = createNativeRouter(routes, {
  beforeEach: async ({ to, from }) => {
    // 可做登录校验、埋点等
    return true;
  },
});

签名:

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<string, any>): Promise
  • replace(to: string, params?: Record<string, any>): Promise
  • back(): void
  • getCurrentLocation(): RouteLocation | null

一般业务只需要通过 RouterProvider + Hooks/Link 使用;直接操作 NativeRouter 适合做底层集成。

createLinking

import { createLinking } from 'react-native-router-dom';

const linking = createLinking(routes, {
  prefixes: ['https://example.com', 'myapp://'],
});

<RouterProvider routes={routes} linking={linking} />;

签名:

type LinkingOptions = {
  prefixes?: string[];
};

function createLinking(routes: RouteProps[], options?: LinkingOptions): {
  prefixes: string[];
  config: { screens: Record<string, any> };
};
  • 默认 prefixes 为 [''],即可直接用 /path 形式的 URL
  • config.screens 结构与 React Navigation linking config 一致

redirect / isRedirect

import { redirect, isRedirect } from 'react-native-router-dom';

router.beforeEach(({ to }) => {
  if (to.pathname.startsWith('/admin') && !isAdmin()) {
    return redirect('/login', { replace: true });
  }
});

签名:

type Redirect = {
  type: 'redirect';
  to: string;
  replace?: boolean;
};

function redirect(to: string, options?: { replace?: boolean }): Redirect;
function isRedirect(value: unknown): value is Redirect;

generatePath

import { generatePath } from 'react-native-router-dom';

const url = generatePath('/user/:id', { id: user.id });
// /user/123

签名:

function generatePath(pattern: string, params?: Record<string, any>): string;
  • pattern 支持 :id、:slug 和 * 通配符

类型导出(TypeScript)

常用类型:

  • RouteProps:路由配置
  • RouteType:'stack' | 'tabs'
  • RouteMeta:Record<string, unknown>
  • RouteGuard / RouteGuardContext / RouteGuardResult
  • Redirect
  • RouteLocation / RouteMatch

所有类型均从包入口导出,可直接:

import type {
  RouteProps,
  RouteLocation,
  RouteMatch,
  RouteGuard,
  RouteGuardContext,
} from 'react-native-router-dom';

在业务项目中,推荐尽量使用这些类型而不是自己手写结构,以便在库升级时获得更好的类型兼容性。