Full minimal reproducable repo is here.
This is a chat app with these routes:
Sidebar
which is also a server componentWhenever I update the data in my Input
component, the sidebar doesn't update even with all of the commands below:
router.refresh();
router.push("/chat/" + chatId);
I even have a special route to invalidate the cache on the server side which calls revalidatePath("/chat", "layout")
but the sidebar still doesn't update.
However, it's weird because in my Sidebar
server component, the shows that it updates but the UI just doesn't update for some reason.
Below are some of the key code snippets, but the full reproducible code is in the repo.
// ./app/chat/layout.tsx
import React from 'react'
import { Sidebar } from "./_sidebar"
export default async function Layout({children}: {children: React.ReactNode}) {
return (
<div className="relative w-screen min-h-screen flex justify-start">
<Sidebar />
{children}
</div>
)
}
// ./app/chat/_sidebar
import { getChats } from "@/actions";
import Link from "next/link";
export async function Sidebar() {
const chats = await getChats();
console.log("Sidebar.chats.latest", chats.at(-1))
return (
<div className="flex flex-col h-full px-6 min-h-screen">
<h2 className="font-bold underline">Sidebar</h2>
<Link href="/chat">New Chat</Link>
{chats.map((chat, index) => (
<p className="whitespace-nowrap" key={index}>{chat.message.slice(0,20)}</p>
))}
</div>
);
}
// ./app/chat/_input.tsx
"use client";
import { nanoid } from "nanoid";
import { useRouter } from "next/navigation";
import React from "react";
export function Input() {
const router = useRouter();
const inputRef = React.useRef<any>();
return (
<div className="absolute bottom-1/2 flex flex-col h-28">
<div className="flex flex-col space-y-8">
<label className="text-white">Input Field Below:</label>
<textarea ref={inputRef} className="text-black w-96 h-48" />
<button
className="bg-green-900 px-6 py-3"
onClick={async () => {
const value = inputRef?.current.value;
const chatId = nanoid();
await fetch("/api/chats/update", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: chatId, message: value }),
}).then(res => res.json());
await fetch(`/api/revalidate?path=/chat&type=layout`, {cache: "no-store"});
router.refresh();
router.push("/chat/" + chatId);
}}
>
Submit
</button>
</div>
</div>
);
}
I found a workaround: just swap the router.push
and router.refresh
rows.
And maybe it doesn't need to call revalidatePath
.
The code below is an example.
<button
className="bg-green-900 px-6 py-3"
onClick={async () => {
const value = inputRef?.current.value;
const chatId = nanoid();
await fetch("/api/chats/update", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: chatId, message: value }),
}).then(res => res.json());
router.push("/chat/" + chatId);
router.refresh();
}}
>
Submit
</button>