vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.72k stars 26.62k forks source link

[Next 13][App-experimental] Mutation pattern using router-refresh not working in built-version #42599

Open Pobermeier opened 1 year ago

Pobermeier commented 1 year ago

Verify canary release

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP Mon Sep 19 19:14:52 UTC 2022
Binaries:
  Node: 16.16.0
  npm: 8.11.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant packages:
  next: 13.0.3-canary.4
  eslint-config-next: 13.0.0
  react: 18.2.0
  react-dom: 18.2.0

What browser are you using? (if relevant)

Chrome 107.0.5304.88 (Chrome is running on Windows 11, my dev env runs in WSL)

How are you deploying your application? (if relevant)

next start, Vercel

Describe the Bug

I've rebuild the example Note-app the Core React-Team created to showcase server-components with Next 13 to try out the new features of the experimental app-directory.

Locally (running the app with next dev), everything is working as expected. However, if I try to run the app in production mode (next build => next start), the CRUD-funtionality of the app does not work anymore as expected. In particular, if I try to either create a new note or delete an existing note, router.refresh() does not work and the list of notes on the left does not update. The app is also hosted here on Vercel.

Expected Behavior

The mutation-pattern with router-refresh works as it does in development mode and the list of notes on the left side of the app UI should be updated with the refreshed list of notes after either creating or deleting a note.

Link to reproduction

https://github.com/Pobermeier/next13-notes-app

To Reproduce

Creating a note:

Deleting a note:

Pobermeier commented 1 year ago

I just updated to the latest canary release. The issue still persists.

timneutkens commented 1 year ago

Had a look into this and the issue is not related to router.refresh() but rather that / is a static page. Seems you're using no-cache but that hasn't been implemented yet, can you try switching it to no-store.

One thing I noticed with regards to the router.refresh() usage is that you're calling router.replace('/') and router.refresh() separately but they should be in a single transition, you can do something like this:

import { startTransition } from 'react'

const deleteNote = async (id: string, router: AppRouterInstance) => {
  const res = await fetch(
    `https://next13-notes-app-api-production.up.railway.app/notes/${id}`,
    {
      method: "delete",
    }
  );

  if (res.ok) {
   startTransition(() => {
      router.replace("/");
      router.refresh()
    });
  }
};

const DeleteButton = ({ id }: DeleteButtonProps) => {
  const router = useRouter();

  return (
    <button
      className="delete-button delete-button--solid"
      onClick={() => deleteNote(id, router)}
    >
      Delete Note
    </button>
  );
};

Or if you want to show a loading indicator you can use useTransition:

import { useTransition } from 'react'
const deleteNote = async (id: string, router: AppRouterInstance, startTransition) => {
  const res = await fetch(
    `https://next13-notes-app-api-production.up.railway.app/notes/${id}`,
    {
      method: "delete",
    }
  );

  if (res.ok) {
    startTransition(() => {
      router.replace("/");
      router.refresh()
    });
  }
};

const DeleteButton = ({ id }: DeleteButtonProps) => {
  const [isPending, startTransition] = useTransition()
  const router = useRouter();

  return (
    <button
      className="delete-button delete-button--solid"
      onClick={() => deleteNote(id, router, startTransition)}
      disabled={isPending}
    >
       {isPending ? 'Deleting note...' : 'Delete Note'}
    </button>
  );
};
Pobermeier commented 1 year ago

@timneutkens: Thank you for looking into this! You're right, I should have read the documentation more carefully. For some reason I thought "no-cache" is the correct setting. After changing it to "no-store" the app works as expected.

Also thank you for your suggestion regarding adding loading states via useTransition!

timneutkens commented 1 year ago

no-cache is supposed to work like no-store but that hasn't been implemented yet 👍 Glad it's working fine now!