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 🙏

© 2024 – Pkg Stats / Ryan Hefner

next-rn

v0.0.20

Published

A set of hooks that wrap the `react-navigation` API that you're used to, and make it work with `next/router`.

Downloads

31

Readme

Next.js Router + React Navigation + More 🥳

A set of hooks that wrap the react-navigation API that you're used to, and make it work with next/router.

This library helps me use the Expo + Next.js integration without stressing about navigation.

This is a new library, PRs are very welcome!

Example

👾 Github Repo | 💻 Website | 📱 Open expo app directly | ☎️ Expo app website

Install

yarn add next-rn

Table of contents

Set up

Step 0. Install next with expo:

  • Init: expo init (or npx create-next-app)

  • Install: yarn add @expo/next-adapter

  • Install next: yarn add next

  • Configure: yarn next-expo

  • Start: yarn next dev

I recommend becoming familiar next's architecture with expo. Follow the Expo docs or see this article by Evan Bacon if you're curious.

Step 1. Edit/create next.config.js

yarn add next-compose-plugins next-fonts next-images next-transpile-modules

Step 2: edit next.config.js to look something like this:

/* eslint-disable @typescript-eslint/no-var-requires */
const { withExpo } = require('@expo/next-adapter')
const withFonts = require('next-fonts')
const withImages = require('next-images')
const withPlugins = require('next-compose-plugins')

const withTM = require('next-transpile-modules')([
  'next-rn',
  // you can add other modules that need traspiling here
])

module.exports = withPlugins(
  [withTM, withFonts, withImages, [withExpo, { projectRoot: __dirname }]],
  {
    // ...
  }
)

Step 3: add this environment variable to .env file: NEXT_PUBLIC_IS_NEXT="true"

All done! Run yarn next dev & open http://localhost:3000 👻

You can add other packages that need transpiling to the transpileModules array. See this post for details.

Usage

Replace the following instances in your code after installation and setup:

useNavigation 👉 useRouting

-import { useNavigation } from '@react-navigation/native'
+import useRouting from 'next-rn/router/use-routing'

useLayoutEffect

-import { useLayoutEffect } from '@react-navigation/native'
+ import { useLayoutEffect } from 'next-rn/use-layout-effect'

<Pressable /> 👉 <Link />

-import { Pressable } from 'react-native'
+import Link from "next-rn/link";

-<Pressable onPress={() => navigate({ routeName: 'chat' })}>
-  <Text>Go</Text>
- </Pressable>
+<Link routeName="chat" params={{ roomId: 'hey!' }}>
+  Go
+</Link>

<Head>

-import Head from "next/head"
+import Head from "next-rn/head";

-<Head>
- <title>page title</title>
-  <meta name="description", content="page description" />
-  <meta name="og:title", content="page title" />
-  <meta name="og:description", content="page description" />
-  <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: 
-    `{
-      "@context": "https://schema.org",
-      "@type": "BreadcrumbList",
-      "itemListElement": [
-        {
-            "@type": "ListItem",
-            "position": 1 ,
-            "name": "Homepage",
-            "item": "https://yourdomain.com/index"
-        },
-        {
-            "@type": "ListItem",
-            "position":  2,
-            "name": "Cart",
-            "item": "https://yourdomain.com/cart"
-        }
-      ]
-    }`
-  }} />
-</Head>
+ <Head metaInfo={{ 
+  title: `page title`,
+  meta: [
+    { hid: "description", name: "description", content: "page +description" },
+    { hid: "og:title", name: "og:title", content: "page title" },
+    { hid: "og:description", name: "og:description", content: +"page description"}`
+  ],
+  script: [
+    {
+      innerHTML: `
+            {
+              "@context": "https://schema.org",
+              "@type": "BreadcrumbList",
+              "itemListElement": [
+                 {
+                     "@type": "ListItem",
+                     "position": 1 ,
+                     "name": "Homepage",
+                     "item": "https://yourdomain.com/index"
+                 },
+                 {
+                     "@type": "ListItem",
+                     "position":  2,
+                     "name": "Cart",
+                     "item": "https://yourdomain.com/cart"
+                 }
+              ]
+            }
+          `,
+      type: "application/ld+json",
+    }
+  ]
+  />
`

<Script>

-import Script from "next/script"
+import Script from "next-rn/script";

<Image>

-import Image from "next/image";
+import Image from "next-rn/image";

All set ⚡️

API

useRouting

React hook that wraps useNavigation (from react-navigation) hook and useRouter (from next-router).

It follows the same API as useNavigation.

import useRouting from "next-rn/router/use-routing"

export default function App() {
  const { navigate, push, getParam, goBack } = useRouting()
}

navigate

Only argument is a dictionary with these values. Unlike react-navigation, this doesn't currently support a string as argument.

  • routeName: string, required
  • params: optional dictionary
  • web: Optional dictionary with added values for web, following the API from next/router's Router.push function.
    • 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.
    • 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.

Example: Navigate to a user

export default function Home() {
  const { navigate } = useRouting()

  // goes to yourdomain.com/user?id=chris
  const onPress = () =>
    navigate({
      routeName: 'user',
      params: { id: 'chris' },
    })

  // 👇or this👇
  // goes to `yourdomain.com/user/chris`
  const navigateCleanLink = () =>
    navigate({
      routeName: 'user',
      params: { id: 'chris' },
      web: { as: `/user/chris` },
    })

  // 👇or this👇
  // 'profile' path overrides 'user' on web, so it uses the pages/profile.js file
  // even though it navigates to yourdomain.com/profile?id=chris?color=blue`
  // ...it actually shows up as yourdomain.com/@chris in the URL bar.
  const navigateCleanLinkWithParam = () =>
    navigate({
      routeName: 'user',
      params: { id: 'chris', color: 'blue' }, // accessed with getParam in the next screen
      web: { as: `/@chris`, path: 'profile' },
    })
}

This follows the next pattern of dynamic routing. You'll need to create a pages/user/[id].js file.

For more thoughts on how and when you should use the web field, see Web Thoughts.

getParam

Same API as getParam from react-navigation.

Similar to query from next/router, except that it's a function to grab the values.

pages/user/[id].js

Imagine you navigated to yourdomain.com/user/chris on web using the example above.

export default function User() {
  const { getParam } = useRouting()

  const id = getParam('id') // chris

  // do something with the id
}

useFocusEffect

See react navigation docs. On web, it simply replaces the focus effect with a normal effect hook. On mobile, it is the exact react navigation hook.

Make sure to use useCallback as seen in the example.

import useFocusEffect from 'next-rn/use-focus-effect'

export default ({ userId }) => {
  useFocusEffect(
    useCallback(() => {
      const unsubscribe = API.subscribe(userId, user => setUser(user))

      return () => unsubscribe()
    }, [userId])
  )

  return <Profile userId={userId} />
}

Head

  • metaInfo :
    • title : string, required
    • meta : array of objects, optional
      • hid : unique identifier
      • name : string
      • content : string
    • script : array of objects
      • type : string
      • innerHTML : any

Script

This component is the same as nextjs Script.

Image

This component works same as Image in react-native.

Link

The following will use the chat route in react navigation.

However, it will use the pages/room.js file for nextjs. Also, it will show up as domain.com/messages in the address bar.

Optionally accepts a nextLinkProps prop dictionary and PressableProps dictionary as well.

export default function Button() {
  return (
    <Link
      routeName="chat"
      params={{ roomId: '12' }}
      web={{
        path: '/room',
        as: 'messages',
      }}
    >
      Chat in room 12
    </Link>
  )
}

Required props:

Optional props

  • web: dictionary, see useRouting().navigate docs. On v1.0.5+, you can also pass the prefetch, replace, and scroll booleans here, from the next/link component.

  • PressableProps: extends React Native's Pressable props.

  • nextLinkProps: extends next/router's Link props.

  • 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.

Web Thoughts

The web prop in the navigate function and Link component can help provide cleaner urls (user/mike instead of user?id=mike) on web.

Also, navigation patterns on mobile can be different than web, and this field can help you account for those situations.

For 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.

This 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:

navigate({
  routeName: 'inboxStack',
  web: {
    path: 'inbox',
  },
})

I've also considered letting the web field take a dynamic parameter like this chat/:roomId:

// goes to `yourdomain.com/chat/chris` and still passes `chris` as a `roomId` param
const navigateCleanLink = () =>
  navigate({
    routeName: 'chat',
    params: { roomId: 'chris' },
    web: { dynamic: `chat/[roomId]` },
  })

// goes to yourdomain.com/chat?roomId=chris
const onPress = () =>
  navigate({
    routeName: 'chat',
    params: { roomId: 'chris' },
  })

But that's not added. For now, the same is achieved by doing this:

const roomId = 'chris'

const navigateToChatRoom = () =>
  navigate({
    routeName: 'chat',
    params: { roomId },
    web: { path: `chat/${roomId}` },
  })

This would open the pages/chat/[roomId].js file, with roomId as a param.