TheSGJ / nextjs-toploader

A Next.js Top Loading Bar component made using nprogress, works with Next.js 14 , Next.js 13 and React.
https://www.npmjs.com/package/nextjs-toploader
MIT License
622 stars 43 forks source link

Compatibility with useRouter #10

Open PixeledCode opened 1 year ago

PixeledCode commented 1 year ago

Great Library. Thanks for your work. So far it works great for Link components but for useRouter, it doesn't seem to work at all. Is there some workaround it?

Edit: After going through multiple comments here, I have settled on this approach https://github.com/CivicDataLab/opub-mono/blob/main/apps/www/lib/navigation.tsx

Aspedm commented 1 year ago

+1, it will be great. But I think it's impossible now, with current app dir api. I'll be glad if I'm wrong.

zbeyens commented 1 year ago

Here is my workaround:

export const usePRouter = () => {
  const router = useRouter();

  const { push } = router;

  router.push = (href, options) => {
    NProgress.start();
    push(href, options);
  };

  return router;
};

// add this to a top level component
const pathname = usePathname();
const searchParams = useSearchParams();

useEffect(() => {
  NProgress.done();
}, [pathname, searchParams]);
PixeledCode commented 1 year ago

Here is my workaround:

export const usePRouter = () => {
  const router = useRouter();

  const { push } = router;

  router.push = (href, options) => {
    NProgress.start();
    push(href, options);
  };

  return router;
};

// add this to a top level component
const pathname = usePathname();
const searchParams = useSearchParams();

useEffect(() => {
  NProgress.done();
}, [pathname, searchParams]);

are you using this library or the nprogress ? where is that NProgress coming from?

zbeyens commented 1 year ago

@PixeledCode Forgot to mention I've forked that library

PixeledCode commented 1 year ago

@PixeledCode Forgot to mention I've forked that library

is your code open? can you share it?

zbeyens commented 1 year ago

@PixeledCode Nothing different than this repo. You just need to import NProgress to start/stop anywhere you want.

import * as NProgress from 'nprogress';
Abesoddy commented 1 year ago

It would be great to have this feature! Thank you for your work! :)

PixeledCode commented 1 year ago

@PixeledCode Nothing different than this repo. You just need to import NProgress to start/stop anywhere you want.

import * as NProgress from 'nprogress';

Thanks for this, this approach worked. I am getting this warning, Entire page /[locale]/dashboard/dataset/new deopted into client-side rendering. and since we are using useSearchParams on top level, I guess this warning will stay, right?

Darren120 commented 1 year ago
import * as NProgress from 'nprogress';

Do you have a workaround with router.refresh() support? most mutations are now just calling refresh to refetch data.

mrsafalpiya commented 1 year ago

@PixeledCode Nothing different than this repo. You just need to import NProgress to start/stop anywhere you want.

import * as NProgress from 'nprogress';

Thanks for this, this approach worked. I am getting this warning, Entire page /[locale]/dashboard/dataset/new deopted into client-side rendering. and since we are using useSearchParams on top level, I guess this warning will stay, right?

This can be fixed by wrapping around the component by react suspense.

<Suspense fallback={null}><NProgressTop /></Suspense>
uixmat commented 1 year ago

Just put your useRouter in a function and include NProgress.start(); as @zbeyens mentioned.

Add:

import * as NProgress from "nprogress";
import { useRouter } from "next/navigation";

Example usage:

const router = useRouter();
const handlePush = () => {
    NProgress.start();
    router.push("/some-page");
};

nextjs-toploader uses NProgress under the hud.

dan-pugsley commented 11 months ago

This progress bar package handles Next 13, both <Link> and router.push() 👍.

You only have to modify your useRouter imports to import { useRouter } from 'next-nprogress-bar'.

Works well!

nodegin commented 9 months ago

@dan-pugsley awesome!

hongaar commented 8 months ago

https://github.com/TheSGJ/nextjs-toploader/issues/10#issuecomment-1538691096 works like a charm, here's a TypeScript version I'm using:

// useRouter.ts

import { useRouter as useBaseRouter } from "next/navigation";
import NProgress from "nprogress";

export function useRouter() {
  const router = useBaseRouter();

  const { push } = router;

  router.push = async (...args: Parameters<typeof push>) => {
    NProgress.start();
    return push(...args);
  };

  return router;
}
lucas-barake commented 8 months ago

If you're using the next/router pages router, this might be of help:

import { useRouter } from "next/router";
import NProgress from "nprogress";

export function useCustomRouter(): ReturnType<typeof useRouter> {
  const router = useRouter();

  const originalPush = router.push;

  router.push = (...args: Parameters<typeof router.push>): ReturnType<typeof originalPush> => {
    NProgress.start();
    return originalPush(...args);
  };

  return router;
}
rodrigocipriani commented 5 months ago

#10 (comment) works like a charm, here's a TypeScript version I'm using:

// useRouter.ts

import { useRouter as useBaseRouter } from "next/navigation";
import NProgress from "nprogress";

export function useRouter() {
  const router = useBaseRouter();

  const { push } = router;

  router.push = async (...args: Parameters<typeof push>) => {
    NProgress.start();
    return push(...args);
  };

  return router;
}

Nice solution, but for me it starts loading and never ends

hongaar commented 5 months ago

Nice solution, but for me it starts loading and never ends

@rodrigocipriani You will probably need to add some code to make the toploader stop spinning, see: https://github.com/TheSGJ/nextjs-toploader/issues/10#issuecomment-1538691096

LuisanSuarez commented 3 months ago

This is not a good solution.

This progress bar package handles Next 13, both <Link> and router.push() 👍.

You only have to modify your useRouter imports to import { useRouter } from 'next-nprogress-bar'.

Works well!

to use this library with Next 13+, you must turn your RootLayout into a client component with 'use client'. this turns your entire app into a client-rendered app, see the docs.

if your server component do any db fetching or use .env vars that are meant to be private (i.e. not prefixed with NEXTPUBLIC), then they will break. you won't be able to directly run server-side database queries on a client environment, and your .env vars will be undefined.

EDIT: fixed broken link to Next docs

PixeledCode commented 3 months ago

This is not a good solution.

This progress bar package handles Next 13, both <Link> and router.push() 👍. You only have to modify your useRouter imports to import { useRouter } from 'next-nprogress-bar'. Works well!

to use this library with Next 13+, you must turn your RootLayout into a client component with 'use client'. this turns your entire app into a client-rendered app, see the docs.

if your server component do any db fetching or use .env vars that are meant to be private (i.e. not prefixed with NEXTPUBLIC), then they will break. you won't be able to directly run server-side database queries on a client environment, and your .env vars will be undefined.

So you have to treat it like any other provider wrapper. Usually you will create a separate Provider component, add all of the components like this and then wrap layout with it. It's a pretty common pattern

LuisanSuarez commented 2 months ago

This is not a good solution. ... if your server component do any db fetching or use .env vars that are meant to be private (i.e. not prefixed with NEXTPUBLIC), then they will break. you won't be able to directly run server-side database queries on a client environment, and your .env vars will be undefined.

So you have to treat it like any other provider wrapper. Usually you will create a separate Provider component, add all of the components like this and then wrap layout with it. It's a pretty common pattern

The Provider pattern is fine too, but you're making a 'use-client' component a parent of all of your app. This turns your entire app into part of the client bundle, and none of it will be server rendered. If you don't care about server rendering it's not an issue. If you do however you can't use next-nprogress-bar.

tomcru commented 2 months ago

You can do this in Holy Loader ↗

'use client';

import { startHolyLoader } from 'holy-loader';

startHolyLoader();
router.push('/your-page')