英文:
Next.js 13 navigation router refresh preserves state
问题
I have this below component and it's included within a Server Component that fetches data and renders it. As it can be seen, I call router.refresh()
on click so it will rerun that page and refetch the data. And it does, but the problem is Next.js keeps preserving this state, so when I call setRefreshing(true)
even though the server component reruns, the refreshing state is still true.
'use client'
import { useRouter } from 'next/navigation'
import Button from './Button'
export default function Refresh() {
const [refreshing, setRefreshing] = useState(false)
const router = useRouter()
const handleClick = () => {
setRefreshing(true)
router.refresh()
}
return (
<Button onClick={handleClick}>
<i className={`bi bi-arrow-repeat text-lg ${refreshing ? 'animate-spin' : ''}`}></i>
Refresh
</Button>
)
}
useEffect
is also not running after refresh, so I can't set it to false in there either. I've found a workaround to pass an array prop to the component, which will then rerun useEffect(() => {...}, [serverHackyProp])
.
<Refresh inProgress={[false]} />
const [[refreshing], setRefreshing] = useState(inProgress)
const router = useRouter()
useEffect(() => {
setRefreshing(inProgress)
}, [inProgress])
const handleClick = () => {
setRefreshing([true])
router.refresh()
}
It works because the passed array will always have a new reference, so useEffect
will run every time the server reruns. But I don't like to do that unless it's my last choice, but I couldn't find a way to setRefreshing(false)
after the router refreshed (server refetched).
英文:
I have this below component and it's included withing a Server Component that fetches data and render it. As it can be seen I call router.refresh()
on click so it will rerun that page and refetch the data. And it does but the problem is Nextjs keep preserving this state, so when i call setRefreshing(true)
even though server component rerun refreshing state is still true.
'use client'
import { useRouter } from 'next/navigation'
import Button from './Button'
export default function Refresh() {
const [refreshing, setRefreshing] = useState(false)
const router = useRouter()
const handleClick = () => {
setRefreshing(true)
router.refresh()
}
return (
<Button onClick={handleClick}>
<i className={`bi bi-arrow-repeat text-lg ${refreshing ? 'animate-spin' : ''}`}></i>
Refresh
</Button>
)
}
useEffect
is also not running after refresh so i can't set it to false in there either. I've found a workaround to pass an array prop to the component which then it will rerun useEffect(() => {...}, [serverHackyProp])
.
<Refresh inProgress={[false]} />
const [[refreshing], setRefreshing] = useState(inProgress)
const router = useRouter()
useEffect(() => {
setRefreshing(inProgress)
}, [inProgress])
const handleClick = () => {
setRefreshing([true])
router.refresh()
}
It works because passed array will always have a new reference so useEffect will run every time server rerun. But I don't like to do that unless it's my last choice but i couldn't find a way to setRefreshing(false)
after router refreshed (server refetched).
答案1
得分: 0
这个问题的一个简单解决方案是让你的数据获取函数在响应中返回一些随机值,并将该随机值用作你的 Refresh
组件的键。这样,每当服务器端数据刷新时,你的 Refresh
组件就会被销毁并重新创建。
// 仅用于测试目的,将 revalidate 设置为 0
export const revalidate = 0;
async function getData() {
return { data: ..., sid: Math.random() };
}
export default async function Page() {
const data = await getData();
return (
<>
<Refresh key={data.sid} />
...
</>
);
}
英文:
One trivial solution to this problem is to have your data fetching function return some random value as part of the response, and use that random value as a key of your Refresh
component. This way your Refresh
component will be teared down and re-created every time server-side data is refreshed.
// setting revalidate to 0 just for the testing purpose
export const revalidate = 0;
async function getData() {
return { data: ..., sid: Math.random() };
}
export default async function Page() {
const data = await getData();
return (
<>
<Refresh key={data.sid} />
...
</>
);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论