Chuyển đến nội dung chính

Day 1 — Làm quen với Next.js 16 và App Router

1. Mục tiêu bài học

Trong ngày đầu tiên, chúng ta sẽ tìm hiểu những khái niệm nền tảng của Next.js 16 và xây dựng một website blog nhỏ để thực hành.

Sau bài học này, bạn có thể:

  • Hiểu Next.js là gì và khác React như thế nào.
  • Khởi tạo project Next.js 16 bằng create-next-app.
  • Hiểu cấu trúc thư mục src/app.
  • Tạo trang bằng page.tsx và layout dùng chung bằng layout.tsx.
  • Phân biệt Server Components và Client Components.
  • Tạo dynamic route với URL dạng /posts/[slug].
  • Hiểu cách sử dụng params trong Next.js 16.
  • Kiểm tra build và xử lý cảnh báo bảo mật từ npm audit.
  • Hiểu nền tảng để kết nối Next.js với một backend API.

2. Next.js là gì?

Next.js là framework được xây dựng dựa trên React, giúp phát triển ứng dụng web hoàn chỉnh. React cung cấp cơ chế xây dựng giao diện bằng component, còn Next.js bổ sung các quy ước về routing, rendering, lấy dữ liệu và tổ chức ứng dụng.

Tính năng Ý nghĩa
App Router Tổ chức trang và layout dựa trên cấu trúc thư mục.
Server Components Cho phép render component phía server theo mặc định trong App Router.
Client Components Hỗ trợ tương tác cần JavaScript phía trình duyệt.
Dynamic Routes Tạo URL động như /posts/what-is-nextjs.
Data Fetching Lấy dữ liệu từ API và các nguồn dữ liệu khác.
Metadata Khai báo tiêu đề, mô tả và thông tin phục vụ SEO.

2.1. React và Next.js khác nhau thế nào?

React là thư viện xây dựng giao diện người dùng. Next.js sử dụng React và cung cấp thêm các quy ước để tổ chức một ứng dụng web.

Với App Router, cấu trúc thư mục thể hiện trực tiếp các URL:

src/app/
├── page.tsx              → /
├── about/
│   └── page.tsx          → /about
└── posts/
    ├── page.tsx          → /posts
    └── [slug]/
        └── page.tsx      → /posts/:slug

Nhờ cách tổ chức này, chúng ta không cần tự xây dựng một hệ thống ánh xạ route riêng cho những trường hợp cơ bản.

2.2. Next.js trong kiến trúc ứng dụng web

Next.js có thể được sử dụng độc lập cho những ứng dụng phù hợp hoặc kết hợp với backend API riêng. Ví dụ, frontend sử dụng Next.js và backend sử dụng ASP.NET Core Web API.

flowchart LR
    A["Người dùng"] --> B["Trình duyệt"]
    B --> C["Next.js"]
    C --> D["ASP.NET Core Web API"]
    D --> E["Database"]
    E --> D
    D --> C
    C --> B
  • Next.js: Quản lý giao diện, routing và hiển thị dữ liệu.
  • ASP.NET Core Web API: Xử lý nghiệp vụ, xác thực và cung cấp dữ liệu.
  • Database: Lưu trữ dữ liệu của ứng dụng.

Trong Day 1, chúng ta chưa cần xây dựng backend. Trước tiên, hãy hiểu cách Next.js tổ chức trang và dữ liệu thông qua một ví dụ đơn giản.

3. Khởi tạo project Next.js 16

3.1. Kiểm tra môi trường

Mở terminal và kiểm tra Node.js cùng npm:

node --version
npm --version

Hãy sử dụng phiên bản Node.js được Next.js hỗ trợ. Tham khảo tài liệu cài đặt chính thức của Next.js để kiểm tra yêu cầu hiện hành.

3.2. Tạo project

Project thực hành được tạo bằng lệnh:

npx create-next-app@latest nextjs-day1-lab --typescript --eslint --app --import-alias "@/*" --use-npm --src-dir

Ý nghĩa các tham số:

Tham số Giải thích
create-next-app@latest Sử dụng phiên bản CLI mới nhất tại thời điểm chạy.
--typescript Sử dụng TypeScript.
--eslint Cấu hình ESLint để kiểm tra mã nguồn.
--app Sử dụng App Router.
--import-alias "@/*" Cấu hình alias @/ cho đường dẫn import.
--use-npm Sử dụng npm để quản lý package.
--src-dir Đặt mã nguồn trong thư mục src.

Trong lần thực hành này, CLI cài đặt Next.js 16.4.0. Để kiểm tra phiên bản thực tế trong project, chạy:

npm ls next react react-dom

Lưu ý: Phiên bản được cài đặt có thể thay đổi theo thời điểm chạy lệnh @latest. Hãy kiểm tra kết quả trong project của bạn.

3.3. Có bắt buộc phải dùng Tailwind CSS không?

Không. CLI có thể chọn template có Tailwind CSS. Bạn vẫn có thể giữ cấu hình đã tạo mà không sử dụng các utility class của Tailwind trong bài học này.

Nếu tạo project mới và không muốn sử dụng Tailwind, có thể thêm tham số --no-tailwind:

npx create-next-app@latest nextjs-day1-lab --typescript --eslint --app --import-alias "@/*" --use-npm --src-dir --no-tailwind

Nếu đã tạo project có Tailwind, không cần tạo lại project chỉ vì lý do này. Trong Day 1, chúng ta sẽ không thêm CSS mới.

4. Xử lý cảnh báo bảo mật sau khi tạo project

Sau khi khởi tạo project, tôi chạy lệnh:

npm audit

Kết quả báo có 5 lỗ hổng mức High. Đây là tình huống có thể gặp ngay cả khi sử dụng CLI chính thức, bởi các package được cài đặt có thể phụ thuộc vào những phiên bản đang có cảnh báo bảo mật.

4.1. Truy tìm dependency gây cảnh báo

Để kiểm tra chuỗi dependency liên quan, chạy:

npm ls next eslint-config-next @next/eslint-plugin-next fast-glob micromatch braces

Kết quả thực tế:

nextjs-day1-lab
+-- eslint-config-next@16.4.0
|   `-- @next/eslint-plugin-next@16.4.0
|       `-- fast-glob@3.3.1
|           `-- micromatch@4.0.8
|               `-- braces@3.0.3
`-- next@16.4.0

Có thể minh họa chuỗi dependency như sau:

flowchart TD
    A["eslint-config-next"]
    B["@next/eslint-plugin-next"]
    C["fast-glob"]
    D["micromatch"]
    E["braces"]
    F["Security Advisory"]

    A --> B --> C --> D --> E --> F

Package liên quan đến cảnh báo là braces, một dependency gián tiếp trong chuỗi công cụ phát triển.

Theo GitHub Security Advisory GHSA-vfj7-8cjw-p6xm, vấn đề được báo cáo liên quan đến việc xử lý brace pattern lồng nhau quá sâu, có thể gây cạn stack và khiến tiến trình Node.js bị dừng.

Cần phân biệt hai khái niệm:

  • Dependency có lỗ hổng: Phiên bản package nằm trong phạm vi bị ảnh hưởng của một advisory.
  • Ứng dụng có thể bị khai thác: Phụ thuộc vào cách package được sử dụng, dữ liệu đầu vào và môi trường thực thi.

Cảnh báo không đồng nghĩa ứng dụng đã bị xâm nhập. Tuy nhiên, cũng không nên bỏ qua cảnh báo mà chưa đánh giá nguyên nhân và phạm vi ảnh hưởng.

4.2. Vì sao không nên chạy ngay npm audit fix --force?

npm đề xuất cách sửa lỗi bằng lệnh:

npm audit fix --force

Trong kết quả thực tế, npm cảnh báo rằng thao tác này có thể cài đặt eslint-config-next@14.2.35, trong khi project đang sử dụng Next.js 16.

Việc hạ phiên bản cấu hình ESLint từ 16 xuống 14 có thể gây không tương thích với cấu hình lint hoặc quy trình build của project.

Vì vậy, tôi không chạy npm audit fix --force một cách máy móc.

Tương tự, không nên tự ép braces sang một phiên bản chưa được xác minh là đã vá. Chỉ nên ghi đè dependency khi đã xác định được phiên bản an toàn, kiểm tra tính tương thích và thử nghiệm kết quả.

4.3. Kiểm tra riêng dependencies production

Tiếp theo, tôi chạy:

npm audit --omit=dev

Kết quả:

found 0 vulnerabilities

Điều này có nghĩa npm không phát hiện lỗ hổng trong nhóm dependency production được kiểm tra.

Chuỗi dependency gây cảnh báo xuất phát từ công cụ ESLint, vốn thường nằm trong nhóm devDependencies. Vì vậy, kết quả kiểm tra toàn bộ dependency tree có thể khác với kết quả kiểm tra riêng production.

Tuy nhiên, kết quả này không chứng minh toàn bộ project đã hoàn toàn an toàn. Các dependency phục vụ phát triển vẫn cần được theo dõi, đặc biệt khi chúng được sử dụng trong CI/CD hoặc môi trường build.

4.4. Cách xử lý trong project hiện tại

Đối với project học tập này, tôi chọn phương án thận trọng:

  1. Giữ nguyên Next.js 16 và phiên bản cấu hình ESLint hiện tại.
  2. Không hạ phiên bản package chỉ để làm biến mất cảnh báo.
  3. Không ép dependency sang phiên bản chưa được xác minh.
  4. Chạy ứng dụng và kiểm tra build.
  5. Theo dõi advisory và kiểm tra lại khi có bản vá tương thích.

Chạy các lệnh sau để kiểm tra:

npm run dev
npm run build
npm audit --omit=dev
npm audit

Đây là cách xử lý tạm thời có kiểm soát, không phải bản vá triệt để cho braces. Với ứng dụng production, cần đánh giá thêm khả năng khai thác, quy trình build và chính sách bảo mật trước khi quyết định chấp nhận rủi ro.

5. Tìm hiểu cấu trúc project

Sau khi cài đặt, cấu trúc project có thể tương tự như sau:

nextjs-day1-lab/
├── public/
├── src/
│   └── app/
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx
│       └── page.tsx
├── eslint.config.mjs
├── next.config.ts
├── package.json
├── package-lock.json
├── tsconfig.json
└── ...
File hoặc thư mục Vai trò
src/app/page.tsx Định nghĩa trang chủ tại URL /.
src/app/layout.tsx Định nghĩa root layout dùng chung.
src/app/globals.css Chứa CSS toàn cục được import vào layout.
public/ Lưu các tài nguyên tĩnh.
package.json Khai báo scripts và dependencies.
next.config.ts Cấu hình Next.js.
tsconfig.json Cấu hình TypeScript.

6. Page và Layout trong App Router

6.1. Tạo trang chủ

Trong App Router, file page.tsx định nghĩa giao diện của một route.

Mở src/app/page.tsx và thay nội dung bằng:

export default function HomePage() {
  return (
    <main>
      <h1>Ứng dụng Next.js 16 đầu tiên</h1>
      <p>Chào mừng bạn đến với Day 1.</p>
    </main>
  );
}

Khởi chạy ứng dụng:

npm run dev

Mở URL được hiển thị trong terminal, thường là http://localhost:3000. Bạn sẽ thấy trang chủ với nội dung vừa tạo.

6.2. Tạo layout dùng chung

Layout giúp nhiều trang sử dụng chung các thành phần như header, navigation và footer.

Mở src/app/layout.tsx. Giữ lại các import cần thiết và điều chỉnh nội dung theo ví dụ sau:

import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "Next.js Day 1 Lab",
  description: "Học Next.js 16 App Router",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="vi">
      <body>
        <header>
          <nav>
            <a href="/">Trang chủ</a>{" | "}
            <a href="/posts">Bài viết</a>
          </nav>
        </header>

        {children}
      </body>
    </html>
  );
}

Đây là ví dụ layout tối giản. Giữ nguyên file CSS được CLI tạo sẵn; bài học này không yêu cầu thêm CSS mới.

Thuộc tính children đại diện cho nội dung của route hiện tại.

flowchart TD
    A["RootLayout"]
    B["Header / Navigation"]
    C["children"]
    D["HomePage"]
    E["PostsPage"]
    F["PostDetailPage"]

    A --> B
    A --> C
    C --> D
    C --> E
    C --> F

Khi người dùng truy cập /, layout hiển thị trang chủ bên trong children. Khi truy cập /posts, phần nội dung sẽ là trang danh sách bài viết.

7. Server Components và Client Components

7.1. Server Components

Trong App Router, component là Server Component theo mặc định, trừ khi module được đánh dấu bằng "use client" tại ranh giới client phù hợp.

Ví dụ:

export default function AboutPage() {
  return (
    <main>
      <h1>Giới thiệu</h1>
      <p>Đây là một Server Component.</p>
    </main>
  );
}

Server Components phù hợp với các trường hợp:

  • Hiển thị nội dung lấy từ nguồn dữ liệu bên ngoài.
  • Truy xuất dữ liệu phía server.
  • Render bài viết hoặc thông tin sản phẩm.
  • Giảm lượng JavaScript phía client khi không cần tương tác.

7.2. Client Components

Khi cần tương tác phía trình duyệt như state hoặc event handler, hãy sử dụng chỉ thị "use client".

Tạo file src/app/components/Counter.tsx:

"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <section>
      <p>Số lần nhấn: {count}</p>

      <button onClick={() => setCount((value) => value + 1)}>
        Tăng
      </button>
    </section>
  );
}

Sử dụng component trong src/app/page.tsx:

import Counter from "./components/Counter";

export default function HomePage() {
  return (
    <main>
      <h1>Ứng dụng Next.js 16 đầu tiên</h1>
      <Counter />
    </main>
  );
}
Tiêu chí Server Component Client Component
Mặc định trong App Router Có Không
React state và event handler phía client Không trực tiếp Có
Hiển thị nội dung từ API Phù hợp trong nhiều trường hợp Phù hợp khi cần tương tác
"use client" Không cần Cần tại ranh giới client

Hai loại component có thể kết hợp với nhau. Việc lựa chọn phụ thuộc vào nhu cầu render, truy xuất dữ liệu và tương tác của từng thành phần.

8. Xây dựng blog nhỏ với Dynamic Routes

Bây giờ chúng ta sẽ tạo một website blog đơn giản để hiểu cách URL được ánh xạ tới trang và cách lấy dữ liệu theo slug.

8.1. Tạo dữ liệu mẫu

Tạo file src/data/posts.ts:

export type Post = {
  slug: string;
  title: string;
  excerpt: string;
  content: string;
};

export const posts: Post[] = [
  {
    slug: "what-is-nextjs",
    title: "Next.js là gì?",
    excerpt: "Giới thiệu về framework Next.js.",
    content:
      "Next.js là framework dựa trên React để xây dựng ứng dụng web.",
  },
  {
    slug: "understanding-app-router",
    title: "Tìm hiểu App Router",
    excerpt: "Cách thư mục và file định nghĩa route.",
    content:
      "App Router sử dụng thư mục app để tổ chức trang, layout và route.",
  },
  {
    slug: "server-and-client-components",
    title: "Server và Client Components",
    excerpt: "Tìm hiểu sự khác nhau giữa hai loại component.",
    content:
      "Server Components phù hợp để render nội dung, còn Client Components hỗ trợ tương tác phía trình duyệt.",
  },
];

Đây là dữ liệu giả lập được lưu trực tiếp trong mã nguồn. Trong ứng dụng thực tế, dữ liệu có thể đến từ API hoặc database.

8.2. Tạo trang danh sách bài viết

Tạo file src/app/posts/page.tsx:

import Link from "next/link";
import { posts } from "@/data/posts";

export default function PostsPage() {
  return (
    <main>
      <h1>Danh sách bài viết</h1>

      <ul>
        {posts.map((post) => (
          <li key={post.slug}>
            <h2>
              <Link href={`/posts/${post.slug}`}>
                {post.title}
              </Link>
            </h2>

            <p>{post.excerpt}</p>
          </li>
        ))}
      </ul>
    </main>
  );
}

Truy cập /posts, bạn sẽ thấy danh sách ba bài viết.

Trong ví dụ này:

  • Link của Next.js hỗ trợ điều hướng giữa các route.
  • map() tạo phần tử giao diện cho mỗi bài viết.
  • key giúp React nhận diện từng phần tử trong danh sách.

8.3. Tạo Dynamic Route

Tạo file:

src/app/posts/[slug]/page.tsx

Thư mục [slug] là một dynamic segment. Ví dụ:

URL Giá trị slug
/posts/what-is-nextjs what-is-nextjs
/posts/understanding-app-router understanding-app-router
/posts/server-and-client-components server-and-client-components

8.4. Xử lý params trong Next.js 16

Trong Next.js 16, params của page là một Promise. Vì vậy, chúng ta cần sử dụng await trước khi đọc giá trị bên trong.

Nội dung file src/app/posts/[slug]/page.tsx:

import { notFound } from "next/navigation";
import { posts } from "@/data/posts";

type PostDetailPageProps = {
  params: Promise<{
    slug: string;
  }>;
};

export default async function PostDetailPage({
  params,
}: PostDetailPageProps) {
  const { slug } = await params;

  const post = posts.find((item) => item.slug === slug);

  if (!post) {
    notFound();
  }

  return (
    <main>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </main>
  );
}

Có ba điểm cần chú ý:

  1. Hàm page được khai báo là async để sử dụng await params.
  2. Kiểu của params được khai báo là Promise trong ví dụ Next.js 16 này.
  3. notFound() xử lý slug không tồn tại bằng cách hiển thị giao diện 404.

8.5. Kiểm tra các route

URL Kết quả mong đợi
/ Trang chủ
/posts Danh sách bài viết
/posts/what-is-nextjs Chi tiết bài viết Next.js
/posts/understanding-app-router Chi tiết bài viết App Router
/posts/unknown-post Trang 404

App Router dựa trên cấu trúc thư mục để ánh xạ các URL này, nên chúng ta không cần tự xây dựng một router riêng cho ví dụ.

9. Kết nối Next.js với ASP.NET Core Web API

Trong ứng dụng thực tế, dữ liệu thường được cung cấp bởi backend API thay vì khai báo trực tiếp trong mã nguồn frontend.

Ví dụ, một ứng dụng có thể sử dụng Next.js làm frontend và ASP.NET Core Web API làm backend:

flowchart LR
    A["Next.js Page"]
    B["ASP.NET Core Web API"]
    C["Database"]

    A -->|"HTTP Request"| B
    B --> C
    C --> B
    B -->|"JSON Response"| A

Backend chịu trách nhiệm xử lý nghiệp vụ và truy xuất dữ liệu. Next.js gọi API, nhận JSON và chuyển dữ liệu thành giao diện.

9.1. Ví dụ gọi API từ Server Component

Giả sử backend cung cấp endpoint GET /api/articles/{slug} và trả về JSON có cấu trúc:

{
  "title": "Giới thiệu Next.js",
  "content": "Đây là bài viết giới thiệu về Next.js."
}

Đây là hợp đồng API minh họa. Bạn cần xây dựng endpoint tương ứng trong backend ASP.NET Core.

Tạo hàm lấy dữ liệu phía server:

type Article = {
  title: string;
  content: string;
};

async function getArticle(slug: string): Promise<Article | null> {
  const baseUrl = process.env.API_BASE_URL;

  if (!baseUrl) {
    throw new Error("API_BASE_URL is not configured");
  }

  const response = await fetch(
    `${baseUrl}/api/articles/${encodeURIComponent(slug)}`
  );

  if (response.status === 404) {
    return null;
  }

  if (!response.ok) {
    throw new Error("Failed to fetch article");
  }

  return response.json() as Promise<Article>;
}

Trong file .env.local, cấu hình địa chỉ backend:

API_BASE_URL=https://localhost:7001

Hãy thay URL bằng địa chỉ thực tế của ASP.NET Core Web API. Không sử dụng tiền tố NEXT_PUBLIC_ cho biến chỉ cần ở phía server.

Trong page, bạn có thể gọi hàm trên sau khi lấy slug từ params:

import { notFound } from "next/navigation";

type Article = {
  title: string;
  content: string;
};

async function getArticle(slug: string): Promise<Article | null> {
  const baseUrl = process.env.API_BASE_URL;

  if (!baseUrl) {
    throw new Error("API_BASE_URL is not configured");
  }

  const response = await fetch(
    `${baseUrl}/api/articles/${encodeURIComponent(slug)}`
  );

  if (response.status === 404) {
    return null;
  }

  if (!response.ok) {
    throw new Error("Failed to fetch article");
  }

  return response.json() as Promise<Article>;
}

export default async function ArticlePage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const article = await getArticle(slug);

  if (!article) {
    notFound();
  }

  return (
    <main>
      <h1>{article.title}</h1>
      <p>{article.content}</p>
    </main>
  );
}

Ví dụ này minh họa cách kết nối frontend và backend. Khi triển khai thực tế, cần bổ sung xử lý lỗi phù hợp, xác thực nếu API yêu cầu, và kiểm tra kiểu dữ liệu trả về thay vì mặc định rằng JSON luôn đúng cấu trúc.

Lưu ý: Nếu Next.js gọi backend trực tiếp từ server, cấu hình CORS thường không phải yếu tố quyết định cho request server-to-server. Nếu trình duyệt gọi API trực tiếp, backend cần cấu hình CORS phù hợp với origin của frontend.

Phần tích hợp API chỉ nhằm giới thiệu hướng phát triển tiếp theo. Day 1 vẫn tập trung vào routing và component; chúng ta chưa cần xây dựng backend để hoàn thành bài thực hành.

10. Kiểm tra ứng dụng và build

Khởi chạy development server:

npm run dev

Kiểm tra các route trong trình duyệt. Sau đó dừng server và chạy:

npm run build

Nếu project có script lint, bạn có thể chạy thêm:

npm run lint

Nếu script này không tồn tại trong package.json, hãy kiểm tra scripts hiện tại thay vì mặc định rằng mọi project Next.js đều có cấu hình giống nhau.

Cuối cùng, kiểm tra lại dependencies:

npm audit --omit=dev
npm audit

Lệnh đầu kiểm tra nhóm production dependencies; lệnh thứ hai kiểm tra dependency tree rộng hơn. Nếu cảnh báo trong development dependencies vẫn còn, hãy ghi nhận và theo dõi thay vì ép hạ phiên bản không tương thích.

11. Tổng kết Day 1

Sau bài học này, bạn cần nhớ những điểm chính:

  • Next.js là framework được xây dựng dựa trên React.
  • App Router ánh xạ cấu trúc thư mục thành URL.
  • page.tsx định nghĩa trang, còn layout.tsx cung cấp cấu trúc giao diện dùng chung.
  • Server Components là mặc định trong App Router.
  • Client Components được sử dụng khi cần tương tác phía trình duyệt.
  • Thư mục [slug] tạo dynamic route.
  • Trong ví dụ Next.js 16 này, params là Promise và cần được await.
  • notFound() xử lý nội dung không tồn tại.
  • Dữ liệu mẫu có thể được thay bằng dữ liệu lấy từ backend API.
  • Khi gặp cảnh báo bảo mật, cần xác định dependency và đánh giá tính tương thích trước khi sửa.

Những nội dung chưa học trong Day 1

  • Chiến lược caching và revalidation.
  • Metadata động theo từng bài viết.
  • Xác thực và phân quyền giữa frontend và backend.
  • Xử lý lỗi API và validation dữ liệu.
  • Deployment và cấu hình production.

12. Bài tập thực hành

Hãy thử tự hoàn thành các bài tập sau mà không sao chép toàn bộ lời giải:

  1. Thêm một bài viết mới vào posts.ts.
  2. Tạo trang /about và thêm liên kết vào navigation.
  3. Truy cập một slug không tồn tại và kiểm tra hành vi 404.
  4. Thêm Client Component có nút tăng số đếm.
  5. Chạy npm run build và ghi lại kết quả.
  6. Chạy cả hai lệnh audit và giải thích vì sao kết quả có thể khác nhau.
  7. Vẽ sơ đồ luồng request từ Next.js đến ASP.NET Core Web API.

Câu hỏi tự kiểm tra

Câu 1: Vì sao file src/app/posts/[slug]/page.tsx có thể xử lý nhiều bài viết mà không cần tạo một file riêng cho từng bài?

Câu 2: Vì sao đoạn code dưới đây không phù hợp với cách sử dụng params trong ví dụ Next.js 16 này?

export default function Page({ params }: { params: { slug: string } }) {
  return <h1>{params.slug}</h1>;
}

Câu 3: Khi nào một component cần chỉ thị "use client"?

Câu 4: Vì sao không nên chạy npm audit fix --force mà chưa xem xét những thay đổi được đề xuất?

Câu 5: Nếu thay dữ liệu mẫu bằng ASP.NET Core Web API, phần routing nào của Next.js có thể giữ nguyên?

13. Kết luận

Day 1 tập trung vào những nền tảng quan trọng: làm quen với App Router, tạo trang và layout, phân biệt Server Components với Client Components, đồng thời xây dựng dynamic route cho một website blog nhỏ.

Phần xử lý npm audit cũng minh họa một kỹ năng cần thiết của lập trình viên: không chỉ làm cho ứng dụng chạy được mà còn phải hiểu dependency, đánh giá rủi ro và xử lý cảnh báo một cách có kiểm soát.

Sau khi nắm vững các kiến thức này, bạn đã có nền tảng để tiếp tục tìm hiểu cách lấy dữ liệu từ API, xử lý dữ liệu và xây dựng ứng dụng web hoàn chỉnh với Next.js.

Hoàn thành Day 1: Next.js 16 App Router, routing, layout, Server và Client Components, kiểm tra dependency và xây dựng blog chạy trên môi trường local.

Tài liệu tham khảo

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.