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 🙏

© 2025 – Pkg Stats / Ryan Hefner

responsive-rsc

v0.0.7

Published

Render cached React Server Components when visiting same search params in page for highly responsive UI

Readme

Responsive RSC

Get Responsiveness of Client Components for React Server Components in Next.js - Instant updates with client-side cached RSCs and Suspense fallbacks.

Conventional way of updating RSCs in Next.js

When using React Server Components (RSCs) in Next.js, The only way to "update" it is by changing it's props. This is usually done by updating the search params of the page using the router from a client component as shown below:

"use client"

function SomeClientComponent() {
  const router = useRouter();
  const pathname = usePathname();

  function handleUpdate(newSearchParams) {
    router.replace(`/${pathname}?${newSearchParams}`);
  }

  return <> ... </>
}

The Problem

When visiting a page again (same pathname + search params) - It still requires doing a round trip to the server to fetch the updated RSCs - Even if the caching is setup properly for fetching the RSC data, it takes some non-zero time and makes the page feel less responsive

Compare this with a fully client rendered component that uses something like React Query or SWR - The UI is updated instantly for cached query and doesn't make any requests to the server. This makes the page feel very responsive.

The Solution

responsive-rsc caches the RSCs and updates them instantly when setting search params that were previously visited in the session and avoids making extra requests to the server. The API also allows updating the component that triggers the update (For example: Filter component) to also update instantly - making the page feel very responsive, similar to a fully client rendered component.

Example Usage

Installation

npm install responsive-rsc

Consider this scenario: There is a Filter component that allows user to select a date range. When user selects a date range, you want to update a server component named Foo component. There is a FooSkeleton component that renders a skeleton that should be shown while the new data is being fetched.

With Responsive RSC, you can:

  • Instantly update the Filter UI when the user selects a new date range and show the FooSkeleton while route transition is pending.
  • If user selects a previously selected date range - the Foo should be updated instantly without making a round trip to the server.

You can achieve this behavior using responsive-rsc as shown below:

Page setup

import { ResponsiveSearchParamsProvider, ResponsiveSuspense } from "responsive-rsc";

type PageProps ={
  // In Next.js >=15 - searchParams is a Promise
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}

export default async function Page(props: PageProps) {
  // get the search params we are interested in
  const searchParams = await props.searchParams;

  // ensure search param is in expected format
  const from = typeof searchParams.from === 'string' ? searchParams.from : undefined;
  const to = typeof searchParams.to === 'string' ? searchParams.to : undefined;

  // set search params in Provider
  return (
    <ResponsiveSearchParamsProvider value={{ from, to }}>
      <Filter />

     {/* Wrap RSC with ResponsiveSuspense */}
     {/* Specify the search params used by RSC in searchParamsUsed prop */}
     {/* Provide skeleton in fallback prop */}
      <ResponsiveSuspense
        searchParamsUsed={["from", "to"]}
        fallback={<FooSkeleton />}
       >
        <Foo from={from} to={to} />
      </ResponsiveSuspense>
    </ResponsiveSearchParamsProvider>
  );
}

// Example RSC component
async function Foo(props: { from?: string, to?: string }) {
  const data = await fetchFooData(props.from, props.to);
  return <FooUI data={data} />;
}

Filter setup

"use client"

import { useResponsiveSearchParams,  useSetResponsiveSearchParams } from "responsive-rsc";

export function Filter() {
  // get searchParams from `useResponsiveSearchParams` to immediately update filter UI when user selects a new date range
  const { from, to } = useResponsiveSearchParams();

  function handleUpdate(newFrom: string, newTo: string) {
    // when this setting new search params -
    // the `Foo` component will immediately suspend and show the `FooSkeleton` if this filter is being set for the first time
    // `Foo` will immediately show data if this filter was set previously and previously shown element will be displayed
    useSetResponsiveSearchParams(v => {
      ...v, // don't overwrite other search params - if any
      from: newFrom,
      to: newTo
    })
  }

  // use `from` and `to` to show the currently selected date range
  // when calling `handleUpdate` with new range - they will be updated instantly - even if new route is still loading
  return <div> ... </div>
}

While this Example only shows a single Filter component and Single RSC - It also works with multiple filters and multiple RSCs on the same page - You just need to follow the same pattern shown above

Important Notes

  • If you use responsive-rsc for a RSC component - all the RSC component that depend on search params must also use responsive-rsc - wrapped in ResponsiveSuspense component.
  • There should only be a single ResponsiveSearchParamsProvider per page
  • When using useSetResponsiveSearchParams hook - you should avoid overwriting other search params by only updating the search params that you are interested in updating - See above example.

License

MIT