跪拜 Guibai
← All articles
Full Stack · JavaScript

Splitting Next.js Server and Client Components for a Redis-Backed Sidebar

By dzhd ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The RSC/client boundary is the central tension in Next.js App Router architecture. This walkthrough makes the split concrete: server components fetch and shape data, while a thin client wrapper reserves space for `useState` and event handlers without pulling the entire list into the browser bundle.

Summary

A Redis hash stores serialized note data, and a four-layer Next.js component tree separates server-side data fetching from client-side interactivity using `children` slots and a `"use client"` boundary. The data layer uses `ioredis` with a seed-data pattern: `hgetall` checks for an empty hash, and `hset` populates sample notes on first run so the UI is never blank. The sidebar component tree splits responsibilities across `Sidebar` (async data fetch), `SidebarNoteList` (array conversion and iteration), `SidebarNoteItem` (date formatting and prop preparation), and `SidebarNoteItemContent` (the `"use client"` boundary reserved for future interaction like expand/collapse). A pre-split version, `SidebarNoteList2`, is kept for comparison to show how inlining everything into one component blocks reuse and interactivity.

Takeaways
Redis is used as an in-memory key-value store, not a relational database, with the `notes` hash mapping string IDs to serialized JSON note objects.
`getAllNotes` in `lib/redis.js` calls `hgetall('notes')`, seeds sample data via `hset` if the hash is empty, and returns the full hash so pages always have content to render.
`Object.entries(notes)` converts the hash object into a two-dimensional array so it can be mapped into React components.
`JSON.parse(note)` deserializes each stored string back into a JavaScript object before passing it to `SidebarNoteItem`.
The component tree is split into four layers: `Sidebar` (async data fetch), `SidebarNoteList` (iterate), `SidebarNoteItem` (format), and `SidebarNoteItemContent` (client boundary).
`SidebarNoteItemContent` is marked `"use client"` and imports `useState` and `useEffect` as placeholders for future expand/collapse interaction, receiving `children` and `expandChildren` as slots.
`dayjs` formats ISO timestamps into readable dates (`YYYY-MM-DD`), and `content.substring(0, 20)` generates a summary with a fallback for empty content.
A pre-split version (`SidebarNoteList2`) inlines everything into one component, contrasting with the split version's single-responsibility design.
Conclusions

The seed-data pattern—checking for an empty hash and populating it on first access—turns a database into a self-initializing module, removing setup steps for demos and development.

Keeping a pre-split component file alongside the refactored version is a practical teaching and comparison technique that production codebases rarely preserve but tutorials benefit from.

The `"use client"` boundary is placed on the innermost leaf component (`SidebarNoteItemContent`), not on the list or item, which keeps the maximum amount of rendering on the server and minimizes client-side JavaScript.

Passing JSX fragments as props (`expandChildren`) rather than strings or flags is a slot pattern that lets the server component own the markup while the client component controls visibility—a clean separation of concerns.

Concepts & terms
Redis Hash
A Redis data type that stores a collection of field-value pairs under a single key. Accessed with commands like `HSET`, `HGET`, and `HGETALL`, it is well-suited for representing objects or records without needing a relational schema.
RSC (React Server Component)
A React component that renders exclusively on the server. It can be `async`, directly access databases or filesystems, and cannot use hooks like `useState` or `useEffect`. It sends serialized output to the client, reducing bundle size.
"use client" directive
A directive placed at the top of a file in Next.js App Router that marks a component and its subtree as client-side. Only components with this directive can use browser APIs, event handlers, and React hooks like `useState`.
Seed data pattern
A strategy where an application checks if a data store is empty on first access and populates it with default or sample data, ensuring the application is immediately usable without manual setup.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗