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-bodies

v1.0.3

Published

Next.js utility to orchestrate main and slave body of app

Downloads

17

Readme

next-bodies

Next.js utility for rendering multiple page components at once based on router pathname while keeping the layout stale. This behavior is also know as contextual modal routing, route as modal. Supports Next.js 10 and dynamic routes (getStaticProps).

  • Example can be found here: https://next-bodies.vercel.app

The most common use case would be to render the next (slave) page in an modal (overlay, dialog) while keeping the current (main) page unchanged and visible, once the user clicks the page link. The same approach is used on Reddit or Instagram posts.

Each page component can specify a custom layout in which the page will be wrapped when rendered as the main page.

Layouts in next-bodies package follow the Adam Wathan Persistent Layouts Patters.

Thank you Adam for your clarification 👍

Using the next-bodies approach for orchestrate page modals includes:

  1. No need to restore scroll positions after back navigation, as the main page is not removed from DOM
  2. No unnecessary re-renders of the main page after the slave page is shown
  3. No unnecessary re-renders of the main page when router pathname did not change
  4. No need to manual opening the overlays - overlays are opened based on router change
  5. No need to manual removing the layout when rendering the page in a dialog
  6. Next.js v10 and dynamic routes (getStaticProps) support

Next.js says: On many popular social media, opening a post will update the URL but won't trigger a navigation and will instead display the content inside a modal. This behavior ensures the user won't lose the current UI context (scroll position). The URL still reflect the post's actual page location and any refresh will bring the user there. This behavior ensures great UX without neglecting SEO.

1. Getting started

A complete example can be seen in the example directory.

Installation

Add the package to your project dependencies

yarn add next-bodies

How to use it

Add the hook call to your _app.ts and specify which page (route) can be rendered in modal (as a slave). In the following example, the main page component is rendered as usual while the slave page component is rendered in the custom dialog (modal) component.

import { AppProps } from 'next/app'
import { createBodiesProps, useBodies } from 'next-bodies'
import Dialog from '../components/dialog/dialog'

/**
 * Defines custom app behavior
 * @param props
 */
function MyApp(props: AppProps) {
  const { router } = props

  // indicates if page can be rendered as slave body component (in modal)
  // you can use your custom logic here (route parsing, query params, ...)
  const renderAsSlave = router.pathname === '/posts/[id]'
  const bodiesProps = createBodiesProps(props)

  // use custom app component manager
  // to be able to render pages in modals
  // while keeping main layout stale
  const {
    mainBody,
    slaveBody: dialogBody,
    useSlave: useDialog,
  } = useBodies(bodiesProps, renderAsSlave)

  return (
    <>
      {mainBody}

      <Dialog isVisible={useDialog}>{dialogBody}</Dialog>
    </>
  )
}

export default MyApp

Alternatively you do not have to use createBodiesProps instead you can provide Component, currentPath, isFallback and pageProps explicitly. See BodiesProps type.

NOTE: Keep in mind that Dialog component in the example above is not part of next-bodies package. It can be replace with any of your custom overlay/modal component.

2. API

const {
  mainBody,
  slaveBody: dialogBody,
  useSlave: useDialog,
} = useBodies(props, renderAsSlave)

Params

  • props - see BodiesProps type
  • renderAsSlave - indicates if the current page component is allowed to render as a slave (usually based on current route)

API

  • mainBody - always contains the first page component to render or any following page component which is not allowed to render as a slave
  • slaveBody - contains the page component which is allowed to render as a slave only when mainBody component already exists
  • useSlave - indicates if slaveBody should be rendered in the current render cycle

BodiesProps

{
  Component: BodyComponent,
  currentPath: string,
  isFallback: boolean,
  pageProps: any
}

3. Layouts

Each page component can specify a custom layout which will be then automatically attached/detached during body rendering. Current page props are pushed as second argument - this is useful for accessing getStaticProps data in layout function.

const IndexPage = () => {
  // ...
}

IndexPage.getLayout = function getLayout(page: ReactNode, pageProps: any) {
  return <Layout>{page}</Layout>
}

export default IndexPage

When no page layout is specified then blank will be used:

const getLayout = CurrentBody.getLayout || ((page, pageProps) => page)