I am using the Next.js App Router architecture, and I have a post page that calls an API and passes the data to a component. I have already implemented simple interactions like clicking to change some styles, etc. However, how can I implement more complex features, such as clicking a button to fetch data again or adding/deleting/updating post? Since I am directly mapping the post data, I can't change the state. I tried storing the post data in useState within useEffect and then mapping through the data in useState, but this loses the SSR effect, and the view-source ends up being empty.
How should I achieve this? Is it possible to sync server data into the initial component? Can the server data be stored globally? Or what should I search for to solve my problem?
// post page
"use client"
import PostItem from "./components/PostItem"
import { useState } from "react"
export default function PostPage() {
const [activeId, setActiveId] = useState(0)
// Assuming it’s data from the API
const post = [
{
id: 101,
title: "How to Learn JavaScript",
content: "JavaScript is a versatile language...",
author: "john_doe",
created_at: "2024-10-01T10:20:30Z",
tags: ["javascript", "programming", "tutorial"],
},
{
id: 102,
title: "Understanding CSS Grid",
content: "CSS Grid is a powerful layout system...",
author: "jane_smith",
created_at: "2024-09-28T14:15:22Z",
tags: ["css", "frontend", "web design"],
},
{
id: 103,
title: "Introduction to React",
content: "React is a popular JavaScript library...",
author: "mark_twain",
created_at: "2024-08-22T08:45:12Z",
tags: ["react", "javascript", "frontend"],
},
]
console.log({ post })
return (
<div className="flex flex-wrap gap-2 mt-4 justify-center items-center">
{post.map((p) => {
return (
<PostItem
key={p.id}
{...p}
onClick={() => setActiveId(p.id)}
isActive={activeId === p.id}
/>
)
})}
</div>
)
}
// post item component
interface PostItemProps {
id: number
title: string
content: string
author: string
created_at: string
tags: Array<string>
isActive?: boolean
onClick: () => void
}
export default function PostItem(props: PostItemProps) {
const { id, title, content, author, created_at, tags, isActive, onClick } =
props
return (
<section
className={`transition-all duration-500 cursor-pointer w-[200px] p-4 ${
isActive
? "bg-blue-700 text-yellow-200 rounded-lg"
: "bg-blue-600 text-white"
} `}
onClick={onClick}
>
<div className="text-xl font-bold mb-2">{title}</div>
<div className="mb-2">{content}</div>
<ul className="mb-2">
{tags.map((t, index) => {
return <li key={index}>{t}</li>
})}
</ul>
</section>
)
}
I tried SSR data passing to components for interaction, but I'm not sure of the correct approach.
YOU CAN FOLLOW THIS APPROACH TO ACHIEVE SSR ALONG WITH OTHER CLIENT EVENTS:
Example code structure:
SSR PAGE:
const fetchPosts=async()=>{
const res = fetch('/posts',{ next: { revalidate: 0 } });
const jsonRes = await res?.json()
return jsonRes;
}
const posts = await fetchPosts();
now you can pass this posts in your client component and on change you can get new data on page. and on each CRUD operation on posts you can call revalidate('/posts') to update posts on your SSR page
I personally follow this approach to achieve SSR along with client side functionality if you find better approach let me know. Happy coding :)