React ViewTransitionを使ってみた。
// nextConfig.js
const nextConfig = {
experimental: {
viewTransition: true,
},
}
export default nextConfig
'use client'
import {
type ReactNode,
unstable_ViewTransition as ViewTransition,
startTransition,
Suspense,
useState,
} from 'react'
import Topltip from '@/_components/Tooltip'
import AnnotaionText from '@/_components/annotation/text'
import { CarouselCard } from '@/_features/blog/blog-carousel-card'
import { type BlogTitlesType } from '@/_features/blog/constant'
interface Carousel {
title: string
contents: BlogTitlesType
}
interface BlogCarouselProps {
carousel: Carousel
}
export default function BlogCarousel({ carousel }: BlogCarouselProps) {
const [orderedContents, setOrderedContents] = useState(carousel.contents)
const reorder = () => {
startTransition(() => {
setOrderedContents((prev) => [...prev.sort(() => Math.random() - 0.5)])
})
}
return (
<>
<Header
title={carousel.title}
action={
<Topltip label="シャッフル">
<button
className="flex items-center rounded-full bg-gray-300 p-1 hover:bg-gray-400"
onClick={reorder}
>
<span className="i-lucide-shuffle h-6 w-6 text-gray-800" />
</button>
</Topltip>
}
/>
<div className="flex gap-6 overflow-x-scroll">
<Suspense fallback={<CarouselCard.Loading />}>
{orderedContents.map((content) => (
<ViewTransition
key={content.year + content.month + content.date + content.title}
>
<CarouselCard {...content} />
</ViewTransition>
))}
</Suspense>
</div>
<div className="flex justify-center">
<AnnotaionText label="※↑意図的に遅延読み込みをしています。" />
</div>
</>
)
}
function Header({ title, action }: { title: string; action?: ReactNode }) {
return (
<div className="flex justify-between">
<span className="i-lucide-arrow-left h-8 w-8 text-gray-300" />
<div className="flex items-center gap-2">
<div className="text-2xl font-bold text-gray-300">{title}</div>
{action}
</div>
<span className="i-lucide-arrow-right h-8 w-8 text-gray-300" />
</div>
)
}