跪拜 Guibai
← All articles
Frontend

A File-by-File Walkthrough of a Next.js + Redis Markdown Note App

By 无糖可可果 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The piece is a tutorial aimed at developers learning Next.js full-stack patterns. It maps the concrete decisions—async server components, Redis hash storage, component extraction—onto a working codebase, making the App Router model tangible for someone who has read the docs but hasn't wired the pieces together.

Summary

A markdown note-taking app built on Next.js and Redis gets a thorough, file-by-file dissection. The walkthrough covers the App Router's file-based routing, the distinction between server and client components via `"use client"`, and how `lib/redis.js` wraps a Redis hash store to serve note data. Every component in the sidebar tree—from `Sidebar` down to `SidebarNoteItemContent`—is explained, including an inline-vs-extracted component comparison.

The project also surfaces practical conventions: alias configuration so `@/` points to the project root, the BEF naming scheme for CSS classes paired with Tailwind, and a "to be continue" comment technique for stubbing future work directly in the code. The data layer uses `ioredis` to store notes as JSON strings in a Redis hash, with seed data that populates the store on first access.

Takeaways
RSC components can be declared `async` so they can `await` backend data fetches before rendering.
`"use client"` at the top of a file marks it as a client component; without it, the component runs on the server by default.
`Object.entries()` converts a Redis hash result into a 2D array, making it straightforward to `map` over in JSX.
Notes are stored in Redis as a hash where the field is a timestamp ID and the value is a JSON-stringified note object, requiring `JSON.parse` on retrieval.
An alias configuration (`@/` → project root) replaces deep relative imports like `../../../lib/redis.js` with clean `@/lib/redis` paths.
The BEF naming convention (Block, Element with `_`, Modifier with `__`) is used alongside Tailwind for maintainable CSS class names.
A side-by-side comparison of `SidebarNoteList.js` (extracted component) and `SidebarNoteList2.js` (inline map) shows the trade-off between reusability and simplicity.
Conclusions

The `SidebarNoteItemContent` component is a deliberate stub: it receives `expandChildren` as a prop but never renders it, which is presented as a feature—a placeholder that signals where future expansion belongs without breaking the current render.

The project treats `initialData` as a seed mechanism inside the data-access function itself rather than a separate migration step, so the Redis store populates automatically on the first read when it's empty.

Calling the comment-driven planning approach 'specification-driven programming' reframes a common habit—leaving TODO comments—as an intentional workflow for breaking work into AI-generable component units.

Concepts & terms
RSC (React Server Component)
A React component that runs on the server. It can be async, fetch data directly, and sends only the rendered output to the client, reducing client-side JavaScript.
Hydration
The process where React attaches event handlers and makes server-rendered HTML interactive on the client. Client components marked with `"use client"` participate in hydration.
BEF Naming Convention
A CSS class-naming scheme: Block (the component root), Element (a part of the block, joined with `_`), and Modifier (a variant, joined with `__`). Used here with Tailwind to keep utility-first styles organized.
Redis Hash
A Redis data type that stores a map of field-value pairs under a single key. In this project, the key is `notes`, each field is a note ID, and each value is a JSON-stringified note object.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗