{"id":51558210,"url":"https://github.com/linguistika/next-rn","last_synced_at":"2026-07-10T08:00:31.296Z","repository":{"id":48668939,"uuid":"376046454","full_name":"Linguistika/next-rn","owner":"Linguistika","description":null,"archived":false,"fork":false,"pushed_at":"2021-12-03T17:31:34.000Z","size":2602,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-24T23:53:56.245Z","etag":null,"topics":["expo","next","nextjs","react","react-native","react-navigation"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/next-rn","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Linguistika.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-11T14:12:17.000Z","updated_at":"2025-06-03T23:03:54.000Z","dependencies_parsed_at":"2022-08-27T07:31:04.332Z","dependency_job_id":null,"html_url":"https://github.com/Linguistika/next-rn","commit_stats":null,"previous_names":["raemundo/next-rn"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Linguistika/next-rn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linguistika%2Fnext-rn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linguistika%2Fnext-rn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linguistika%2Fnext-rn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linguistika%2Fnext-rn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Linguistika","download_url":"https://codeload.github.com/Linguistika/next-rn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Linguistika%2Fnext-rn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35325188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expo","next","nextjs","react","react-native","react-navigation"],"created_at":"2026-07-10T08:00:21.536Z","updated_at":"2026-07-10T08:00:31.242Z","avatar_url":"https://github.com/Linguistika.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n\n  \n\n# Next.js Router + React Navigation + More 🥳\n\nA set of hooks that wrap the `react-navigation` API that you're used to, and make it work with `next/router`.\n\nThis library helps me use the [Expo + Next.js integration](https://docs.expo.io/versions/latest/guides/using-nextjs/) without stressing about navigation.\n\n_This is a new library, PRs are very welcome!_\n\n## Example\n\n👾 [Github Repo](https://github.com/raemundo/next-rn/tree/main/examples/with-next) | 💻 [Website]() | 📱 [Open expo app directly]() | ☎️ [Expo app website]()\n\n## Install\n\n```sh\nyarn add next-rn\n```\n## Table of contents\n\n- [Set up](#set-up)\n- [Usage](#usage)\n- Hooks\n  - [`useRouting`](#userouting)\n  - [`useFocusEffect`](#useFocusEffect)\n- Components\n  - [`Head`](#head)\n  - [`Script`](#script)\n  - [`Image`](#image)\n  - [`Link`](#link)\n  \n## Set up\n\n**Step 0. Install next with expo:**\n\n- Init: `expo init` (or `npx create-next-app`)\n\n- Install: `yarn add @expo/next-adapter`\n\n- Install next: `yarn add next`\n\n- Configure: `yarn next-expo`\n\n- Start: `yarn next dev`\n\n_I recommend becoming familiar `next`'s architecture with `expo`. Follow the [Expo docs](https://docs.expo.io/versions/latest/guides/using-nextjs/) or see [this article](https://dev.to/evanbacon/next-js-expo-and-react-native-for-web-3kd9) by Evan Bacon if you're curious._\n\n**Step 1. Edit/create next.config.js**\n\n```bash\nyarn add next-compose-plugins next-fonts next-images next-transpile-modules\n```\n\n**Step 2: edit `next.config.js` to look something like this:**\n\n```es6\n/* eslint-disable @typescript-eslint/no-var-requires */\nconst { withExpo } = require('@expo/next-adapter')\nconst withFonts = require('next-fonts')\nconst withImages = require('next-images')\nconst withPlugins = require('next-compose-plugins')\n\nconst withTM = require('next-transpile-modules')([\n  'next-rn',\n  // you can add other modules that need traspiling here\n])\n\nmodule.exports = withPlugins(\n  [withTM, withFonts, withImages, [withExpo, { projectRoot: __dirname }]],\n  {\n    // ...\n  }\n)\n```\n\n**Step 3: add this environment variable to .env file:**\n```NEXT_PUBLIC_IS_NEXT=\"true\"```\n\n**All done! Run `yarn next dev` \u0026 open [http://localhost:3000](http://localhost:3000)** 👻\n\n- Take a look at the [next tutorial](https://nextjs.org/learn/basics/create-dynamic-pages) for creating pages.\n\n_You can add other packages that need transpiling to the `transpileModules` array. See [this post](https://forums.expo.io/t/next-js-expo-web-syntaxerror-unexpected-token-export-with-npm-module/31127) for details._\n\n## Usage\n\nReplace the following instances in your code after installation and setup:\n\n### `useNavigation` 👉 `useRouting`\n\n```diff\n-import { useNavigation } from '@react-navigation/native'\n+import useRouting from 'next-rn/router/use-routing'\n```\n\n### `useLayoutEffect`\n\n```diff\n-import { useLayoutEffect } from '@react-navigation/native'\n+ import { useLayoutEffect } from 'next-rn/use-layout-effect'\n```\n\n### `\u003cPressable /\u003e` 👉 `\u003cLink /\u003e`\n\n```diff\n-import { Pressable } from 'react-native'\n+import Link from \"next-rn/link\";\n\n-\u003cPressable onPress={() =\u003e navigate({ routeName: 'chat' })}\u003e\n-  \u003cText\u003eGo\u003c/Text\u003e\n- \u003c/Pressable\u003e\n+\u003cLink routeName=\"chat\" params={{ roomId: 'hey!' }}\u003e\n+  Go\n+\u003c/Link\u003e\n```\n### `\u003cHead\u003e`\n```diff\n-import Head from \"next/head\"\n+import Head from \"next-rn/head\";\n\n-\u003cHead\u003e\n- \u003ctitle\u003epage title\u003c/title\u003e\n-  \u003cmeta name=\"description\", content=\"page description\" /\u003e\n-  \u003cmeta name=\"og:title\", content=\"page title\" /\u003e\n-  \u003cmeta name=\"og:description\", content=\"page description\" /\u003e\n-  \u003cscript type=\"application/ld+json\" dangerouslySetInnerHTML={{ __html: \n-    `{\n-      \"@context\": \"https://schema.org\",\n-      \"@type\": \"BreadcrumbList\",\n-      \"itemListElement\": [\n-        {\n-            \"@type\": \"ListItem\",\n-            \"position\": 1 ,\n-            \"name\": \"Homepage\",\n-            \"item\": \"https://yourdomain.com/index\"\n-        },\n-        {\n-            \"@type\": \"ListItem\",\n-            \"position\":  2,\n-            \"name\": \"Cart\",\n-            \"item\": \"https://yourdomain.com/cart\"\n-        }\n-      ]\n-    }`\n-  }} /\u003e\n-\u003c/Head\u003e\n+ \u003cHead metaInfo={{ \n+  title: `page title`,\n+  meta: [\n+    { hid: \"description\", name: \"description\", content: \"page +description\" },\n+    { hid: \"og:title\", name: \"og:title\", content: \"page title\" },\n+    { hid: \"og:description\", name: \"og:description\", content: +\"page description\"}`\n+  ],\n+  script: [\n+    {\n+      innerHTML: `\n+            {\n+              \"@context\": \"https://schema.org\",\n+              \"@type\": \"BreadcrumbList\",\n+              \"itemListElement\": [\n+                 {\n+                     \"@type\": \"ListItem\",\n+                     \"position\": 1 ,\n+                     \"name\": \"Homepage\",\n+                     \"item\": \"https://yourdomain.com/index\"\n+                 },\n+                 {\n+                     \"@type\": \"ListItem\",\n+                     \"position\":  2,\n+                     \"name\": \"Cart\",\n+                     \"item\": \"https://yourdomain.com/cart\"\n+                 }\n+              ]\n+            }\n+          `,\n+      type: \"application/ld+json\",\n+    }\n+  ]\n+  /\u003e\n`\n```\n### `\u003cScript\u003e`\n```diff\n-import Script from \"next/script\"\n+import Script from \"next-rn/script\";\n```\n### `\u003cImage\u003e`\n```diff\n-import Image from \"next/image\";\n+import Image from \"next-rn/image\";\n```\n\n\n\nAll set ⚡️\n\n# API\n\n## `useRouting`\n\nReact hook that wraps `useNavigation` (from react-navigation) hook and `useRouter` (from next-router).\n\nIt follows the [same API](https://reactnavigation.org/docs/en/next/use-navigation.html) as `useNavigation`.\n\n```es6\nimport useRouting from \"next-rn/router/use-routing\"\n\nexport default function App() {\n  const { navigate, push, getParam, goBack } = useRouting()\n}\n```\n\n### `navigate`\n\nOnly argument is a dictionary with these values. Unlike `react-navigation`, this doesn't currently support a string as argument.\n\n- `routeName`: string, required\n- `params`: optional dictionary\n- `web`: Optional dictionary with added values for web, following the API from `next/router`'s `Router.push` [function](https://nextjs.org/docs#with-url-object-1).\n  - `path`: (optional) Fulfills the same value as `pathname` from `next/router`, overriding the `routeName` field. If you set this to `/cars`, it will navigate to `/cars` instead of the `routeName` field. As a result, it will load the file located at `pages/cars.js`.\n  - `as`: (optional) If set, the browser will show this value in the address bar. Useful if you want to show a pretty/custom URL in the address bar that doesn't match the actual path. Unlike the `path` field, this does not affect which route you actually go to.\n\n**Example:** Navigate to a user\n\n```es6\nexport default function Home() {\n  const { navigate } = useRouting()\n\n  // goes to yourdomain.com/user?id=chris\n  const onPress = () =\u003e\n    navigate({\n      routeName: 'user',\n      params: { id: 'chris' },\n    })\n\n  // 👇or this👇\n  // goes to `yourdomain.com/user/chris`\n  const navigateCleanLink = () =\u003e\n    navigate({\n      routeName: 'user',\n      params: { id: 'chris' },\n      web: { as: `/user/chris` },\n    })\n\n  // 👇or this👇\n  // 'profile' path overrides 'user' on web, so it uses the pages/profile.js file\n  // even though it navigates to yourdomain.com/profile?id=chris?color=blue`\n  // ...it actually shows up as yourdomain.com/@chris in the URL bar.\n  const navigateCleanLinkWithParam = () =\u003e\n    navigate({\n      routeName: 'user',\n      params: { id: 'chris', color: 'blue' }, // accessed with getParam in the next screen\n      web: { as: `/@chris`, path: 'profile' },\n    })\n}\n```\n\nThis follows the next pattern of [dynamic routing](https://nextjs.org/learn/basics/clean-urls-with-dynamic-routing). You'll need to create a `pages/user/[id].js` file.\n\nFor more thoughts on how and when you should use the `web` field, see [Web Thoughts](#web-thoughts).\n\n### `getParam`\n\n[Same API](https://reactnavigation.org/docs/en/navigation-prop.html#getparam-get-a-specific-param-value-with-a-fallback) as `getParam` from react-navigation.\n\nSimilar to `query` from `next/router`, except that it's a function to grab the values.\n\n**pages/user/[id].js**\n\nImagine you navigated to `yourdomain.com/user/chris` on web using the example above.\n\n```es6\nexport default function User() {\n  const { getParam } = useRouting()\n\n  const id = getParam('id') // chris\n\n  // do something with the id\n}\n```\n\n## `useFocusEffect`\n\nSee [react navigation docs](https://reactnavigation.org/docs/en/next/use-focus-effect.html#docsNav). On web, it simply replaces the focus effect with a normal effect hook. On mobile, it is the exact react navigation hook.\n\nMake sure to use [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback) as seen in the example.\n\n```es6\nimport useFocusEffect from 'next-rn/use-focus-effect'\n\nexport default ({ userId }) =\u003e {\n  useFocusEffect(\n    useCallback(() =\u003e {\n      const unsubscribe = API.subscribe(userId, user =\u003e setUser(user))\n\n      return () =\u003e unsubscribe()\n    }, [userId])\n  )\n\n  return \u003cProfile userId={userId} /\u003e\n}\n```\n## `Head`\n\n - `metaInfo` : \n\t - `title` : string, required\n\t - `meta` : array of objects, optional\n\t\t - hid : unique identifier\n\t\t - name : string\n\t\t - content : string\n\t - `script` : array of objects\n\t\t - `type` : string\n\t\t - `innerHTML` : any\n\n## `Script`\nThis component is the same as [nextjs Script.](https://nextjs.org/docs/basic-features/script) \n## `Image`\nThis component works same as `Image` in [react-native](https://reactnative.dev/docs/image).\n## `Link`\n\nThe following will use the `chat` route in react navigation.\n\nHowever, it will use the `pages/room.js` file for nextjs. Also, it will show up as `domain.com/messages` in the address bar.\n\nOptionally accepts a `nextLinkProps` prop dictionary and `PressableProps` dictionary as well.\n\n```es6\nexport default function Button() {\n  return (\n    \u003cLink\n      routeName=\"chat\"\n      params={{ roomId: '12' }}\n      web={{\n        path: '/room',\n        as: 'messages',\n      }}\n    \u003e\n      Chat in room 12\n    \u003c/Link\u003e\n  )\n}\n```\n\n**Required props**:\n\n- `routeName`: string, see [`useRouting().navigate`](https://github.com/raemundo/next-rn#navigate) docs.\n- `children`: string\n\n**Optional props**\n\n- `web`: dictionary, see [`useRouting().navigate`](#navigate) docs. On `v1.0.5`+, you can also pass the `prefetch`, `replace`, and `scroll` booleans here, from the `next/link` [component](https://nextjs.org/docs/api-reference/next/link).\n\n- `PressableProps`: extends React Native's `Pressable` props.\n\n- `nextLinkProps`: extends `next/router`'s [Link props](https://nextjs.org/docs#with-link).\n- `isText`: if false, you can set the children to be non-Text nodes. Defaults to `true`. If `true`, the children can be a string **or** a `Text` node.\n\n## Web Thoughts\n\nThe `web` prop in the `navigate` function and `Link` component can help provide cleaner urls (`user/mike` instead of `user?id=mike`) on web.\n\nAlso, navigation patterns on mobile can be different than web, and this field can help you account for those situations.\n\nFor instance, imagine you have a tab navigator. Say the first tab has a nested stack navigator with an inbox screen and a chat room screen. If you navigate from a notifications tab to this tab, and a chat room screen was already open, you probably want that chat room to stay open on mobile. Only if you press the tab button a second time should it pop back to the inbox screen.\n\nThis may not be the case on `web`. Web navigation patterns on web may lead you to want to open the inbox directly, instead of the open chat screen. This example could look something like this:\n\n```es6\nnavigate({\n  routeName: 'inboxStack',\n  web: {\n    path: 'inbox',\n  },\n})\n```\n\nI've also considered letting the `web` field take a `dynamic` parameter like this `chat/:roomId`:\n\n```es6\n// goes to `yourdomain.com/chat/chris` and still passes `chris` as a `roomId` param\nconst navigateCleanLink = () =\u003e\n  navigate({\n    routeName: 'chat',\n    params: { roomId: 'chris' },\n    web: { dynamic: `chat/[roomId]` },\n  })\n\n// goes to yourdomain.com/chat?roomId=chris\nconst onPress = () =\u003e\n  navigate({\n    routeName: 'chat',\n    params: { roomId: 'chris' },\n  })\n```\n\nBut that's not added. For now, the same is achieved by doing this:\n\n```es6\nconst roomId = 'chris'\n\nconst navigateToChatRoom = () =\u003e\n  navigate({\n    routeName: 'chat',\n    params: { roomId },\n    web: { path: `chat/${roomId}` },\n  })\n```\n\nThis would open the `pages/chat/[roomId].js` file, with `roomId` as a param.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinguistika%2Fnext-rn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinguistika%2Fnext-rn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinguistika%2Fnext-rn/lists"}