Next.js có năm loại mẫu lấy dữ liệu để xác định cách bạn muốn nội dung được hiển thị trong ứng dụng của mình: tạo trang tĩnh (SSG), kết xuất phía máy chủ (SSR), kết xuất phía máy khách (CSR), tái tạo tĩnh gia tăng (ISR) và định tuyến động.
Bạn có thể chọn bất kỳ mẫu nào trong số các mẫu này phù hợp với cấu trúc ứng dụng của mình. Để tìm hiểu thêm về các mẫu này, hãy đọc về chúng trong tài liệu chính thức.
Bài viết này tập trung vào việc tạo trang tĩnh và định tuyến động. Việc sử dụng các mẫu này yêu cầu phải sử dụng các phương thức lấy dữ liệu
Chúng ta đã nói về dữ liệu động trong một thời gian rồi. Hãy cùng tìm hiểu ý nghĩa thực sự của điều đó.
Giả sử chúng ta có danh sách người dùng trong một ứng dụng được hiển thị trên một trang web và chúng ta muốn có thông tin duy nhất về một người dùng khi chúng ta nhấp vào tên của họ — thông tin chúng ta nhận được sẽ thay đổi tùy theo hành động chúng ta thực hiện (nhấp vào tên người dùng).
Chúng ta muốn có một cách để hiển thị dữ liệu đó trên một trang (hoặc màn hình) duy nhất trong ứng dụng và phương thức lấy dữ liệu
Khóa duy nhất thu được từ phương thức
Điều này đưa chúng ta trở lại thực tế là
Có thể lấy dữ liệu từ API công khai không yêu cầu xác thực bằng một số loại khóa API trong quá trình lấy dữ liệu bằng
Hãy xem cả hai phương thức bên dưới:
Bạn sẽ thấy rằng
Trong đoạn trích trên, bạn sẽ thấy một biến có tên
Sau đó, giá trị đó được thêm dưới dạng tham số vào URL cơ sở của API.
Lưu ý: Các phương thức lấy dữ liệu
Về cơ bản, đó là tất cả những gì cần làm đối với một API công khai. Nhưng khi bạn xây dựng một ứng dụng yêu cầu người dùng đăng nhập, đăng xuất và có thể thực hiện một số thao tác lấy dữ liệu trong ứng dụng khi họ đăng nhập bằng tài khoản của mình, thì luồng ứng dụng sẽ khác.
Hãy hình dung tình huống này: Người dùng đăng nhập vào ứng dụng web rồi truy cập hồ sơ của họ. Trên trang hồ sơ của họ (sau khi được hiển thị), họ có thể xem và thay đổi thông tin mà họ đã cung cấp khi đăng ký.
Để điều này xảy ra, phải có một số loại xác minh dữ liệu được gửi đến người dùng bởi nhà phát triển đã xây dựng giao diện. May mắn thay, có một mẫu chung để ủy quyền cho người dùng khi họ đăng nhập vào hệ thống: JSON Web Tokens (JWT).
Khi người dùng đăng ký sử dụng ứng dụng của bạn lần đầu tiên, thông tin chi tiết của họ sẽ được lưu trữ trong cơ sở dữ liệu và một JWT duy nhất sẽ được gán cho lược đồ của người dùng đó (tùy thuộc vào cách thiết kế API phụ trợ).
Khi người dùng cố gắng đăng nhập vào ứng dụng của bạn và thông tin đăng nhập của họ khớp với thông tin họ đã đăng ký ban đầu, thì việc tiếp theo chúng tôi, những kỹ sư front-end, phải làm là cung cấp trạng thái xác thực cho người dùng để có thể lấy được thông tin chi tiết cần thiết, một trong số đó là JWT.
Có nhiều trường phái khác nhau về cách bảo toàn
Cách tiếp cận phổ biến là lưu trữ JWT trong
Một lần nữa, cách tiếp cận này chỉ có thể thực hiện được nếu phần mềm trung gian cookie phù hợp được cung cấp trong API mà các kỹ sư phụ trợ đã xây dựng.
Nếu bạn không muốn mất công tìm hiểu cách các kỹ sư phụ trợ thiết kế API, một cách thay thế để xác thực trong Next.js là sử dụng dự án xác thực nguồn mở NextAuth.js.
Khi mã thông báo nằm trong
Lấy dữ liệu bằng Hook
Trong phần đầu tiên, chúng ta đã thấy quy trình lấy dữ liệu động hoạt động như thế nào trong Next.js đối với một ứng dụng không yêu cầu xác thực.
Trong phần này, chúng ta sẽ xem cách bỏ qua sự cố của các phương thức lấy dữ liệu
Lỗi này xảy ra vì hai phương thức lấy dữ liệu luôn chạy trên máy chủ ở chế độ nền, do đó, đối tượng
API bộ định tuyến của Next.js tạo ra nhiều khả năng khi chúng ta xử lý các tuyến động và dữ liệu. Với hook
Hãy xem đoạn trích bên dưới để bắt đầu:
Trong đoạn trích trên, chúng tôi đã sử dụng hook
Khi chúng ta nhấp vào một người dùng, thành phần
Móc
Đoạn trích dưới đây minh họa toàn bộ quá trình:
Trong đoạn trích trên, bạn sẽ thấy rằng chúng tôi đã giải cấu trúc đối tượng truy vấn từ hook
Sau khi ID duy nhất được thêm vào điểm cuối API, dữ liệu dành cho người dùng đó sẽ được hiển thị sau khi trang được tải.
Tôi hy vọng bài viết này đã giúp bạn hiểu cách sử dụng API bộ định tuyến của Next.js để lấy dữ liệu động trong ứng dụng của mình.
Bạn có thể chọn bất kỳ mẫu nào trong số các mẫu này phù hợp với cấu trúc ứng dụng của mình. Để tìm hiểu thêm về các mẫu này, hãy đọc về chúng trong tài liệu chính thức.
Bài viết này tập trung vào việc tạo trang tĩnh và định tuyến động. Việc sử dụng các mẫu này yêu cầu phải sử dụng các phương thức lấy dữ liệu
getStaticProps
và getStaticPaths
. Các phương thức này đóng vai trò riêng trong việc lấy dữ liệu.Chúng ta đã nói về dữ liệu động trong một thời gian rồi. Hãy cùng tìm hiểu ý nghĩa thực sự của điều đó.
Giả sử chúng ta có danh sách người dùng trong một ứng dụng được hiển thị trên một trang web và chúng ta muốn có thông tin duy nhất về một người dùng khi chúng ta nhấp vào tên của họ — thông tin chúng ta nhận được sẽ thay đổi tùy theo hành động chúng ta thực hiện (nhấp vào tên người dùng).
Chúng ta muốn có một cách để hiển thị dữ liệu đó trên một trang (hoặc màn hình) duy nhất trong ứng dụng và phương thức lấy dữ liệu
getStaticPaths
cho phép chúng ta có được dữ liệu duy nhất về một người dùng. Điều này thường phổ biến trong một mảng các đối tượng người dùng có khóa duy nhất (id
hoặc _id
), tùy thuộc vào cách đối tượng phản hồi được cấu trúc.
Mã:
export async function getStaticPaths() { return { paths: { [{ params: { uniqueId: id.toString() } }], fallback: false } }}
getStaticPaths
(thường được gọi là tham số hoặc viết tắt là params) được truyền dưới dạng đối số thông qua tham số context
trong getStaticProps
.Điều này đưa chúng ta trở lại thực tế là
getStaticPaths
không thể hoạt động nếu không có getStaticProps
. Cả hai đều hoạt động cùng nhau vì bạn sẽ cần truyền id
duy nhất từ đường dẫn được tạo tĩnh dưới dạng đối số cho tham số context
trong getStaticProps
. Đoạn mã dưới đây minh họa điều này:
Mã:
export async function getStaticProps(context) { return { props: { userData: data, }, }}
Nhược điểm của việc sử dụng các phương thức lấy dữ liệu gốc của Next.js
Bây giờ chúng ta đã hiểu một chút về việc lấy dữ liệu động trong Next.js, hãy cùng xem xét nhược điểm của việc sử dụng hai phương thức lấy dữ liệu đã đề cập ở trên.Có thể lấy dữ liệu từ API công khai không yêu cầu xác thực bằng một số loại khóa API trong quá trình lấy dữ liệu bằng
getStaticProps
và getStaticPaths
.Hãy xem cả hai phương thức bên dưới:
Mã:
// getStaticPathsexport async function getStaticPaths() { const response = fetch("https://jsonplaceholder.typicode.com/users") const userData = await response.json() // Lấy khóa duy nhất của người dùng từ phản hồi // bằng phương thức map của JavaScript. const uniqueId = userData.map((data) => { return data.id }) return { paths: { [{ params: { uniqueId: uniqueId.toString() } }], fallback: false } }}
id
duy nhất được lấy từ phương thức map
của JavaScript và chúng ta sẽ gán nó dưới dạng giá trị thông qua tham số context
của getStaticProps
.
Mã:
export async function getStaticProps(context) { // Lấy ID duy nhất của người dùng. const userId = context.params.uniqueId // Thêm ID dưới dạng tham số vào điểm cuối API. const response = fetch(`https://jsonplaceholder.typicode.com/users/${userId}`) const userData = await response.json() return { props: { userData, }, }}
userId
đã được khởi tạo và giá trị của biến này được lấy từ tham số context
.Sau đó, giá trị đó được thêm dưới dạng tham số vào URL cơ sở của API.
Lưu ý: Các phương thức lấy dữ liệu
getStaticProps
và getStaticPaths
chỉ có thể được xuất từ một tệp trong thư mục pages
của Next.js.Về cơ bản, đó là tất cả những gì cần làm đối với một API công khai. Nhưng khi bạn xây dựng một ứng dụng yêu cầu người dùng đăng nhập, đăng xuất và có thể thực hiện một số thao tác lấy dữ liệu trong ứng dụng khi họ đăng nhập bằng tài khoản của mình, thì luồng ứng dụng sẽ khác.
Lấy dữ liệu trong hệ thống đã xác thực.
Quy trình thu thập dữ liệu trong hệ thống đã xác thực khá khác so với cách thông thường chúng ta thu thập dữ liệu từ API công khai.Hãy hình dung tình huống này: Người dùng đăng nhập vào ứng dụng web rồi truy cập hồ sơ của họ. Trên trang hồ sơ của họ (sau khi được hiển thị), họ có thể xem và thay đổi thông tin mà họ đã cung cấp khi đăng ký.
Để điều này xảy ra, phải có một số loại xác minh dữ liệu được gửi đến người dùng bởi nhà phát triển đã xây dựng giao diện. May mắn thay, có một mẫu chung để ủy quyền cho người dùng khi họ đăng nhập vào hệ thống: JSON Web Tokens (JWT).
Khi người dùng đăng ký sử dụng ứng dụng của bạn lần đầu tiên, thông tin chi tiết của họ sẽ được lưu trữ trong cơ sở dữ liệu và một JWT duy nhất sẽ được gán cho lược đồ của người dùng đó (tùy thuộc vào cách thiết kế API phụ trợ).
Khi người dùng cố gắng đăng nhập vào ứng dụng của bạn và thông tin đăng nhập của họ khớp với thông tin họ đã đăng ký ban đầu, thì việc tiếp theo chúng tôi, những kỹ sư front-end, phải làm là cung cấp trạng thái xác thực cho người dùng để có thể lấy được thông tin chi tiết cần thiết, một trong số đó là JWT.
Có nhiều trường phái khác nhau về cách bảo toàn
trạng thái xác thực
của người dùng, bao gồm sử dụng Redux, Composition trong React và API Context của React (tôi khuyên dùng API Context). Bài viết của Átila Fassina đề cập đến các mô hình quản lý trạng thái trong Next.js.Cách tiếp cận phổ biến là lưu trữ JWT trong
localStorage
— ít nhất là để bắt đầu, nếu chúng ta đang xem xét vấn đề bảo mật theo cách nghiêm ngặt. Nên lưu trữ JWT của bạn trong cookie httpOnly
để ngăn chặn các cuộc tấn công bảo mật như làm giả yêu cầu chéo trang (CSRF) và mã lệnh chéo trang (XSS).Một lần nữa, cách tiếp cận này chỉ có thể thực hiện được nếu phần mềm trung gian cookie phù hợp được cung cấp trong API mà các kỹ sư phụ trợ đã xây dựng.
Nếu bạn không muốn mất công tìm hiểu cách các kỹ sư phụ trợ thiết kế API, một cách thay thế để xác thực trong Next.js là sử dụng dự án xác thực nguồn mở NextAuth.js.
Khi mã thông báo nằm trong
localStorage
ở phía máy khách, các lệnh gọi API yêu cầu mã thông báo của người dùng làm phương tiện xác thực có thể được thực hiện mà không gây ra lỗi 501 (không được ủy quyền).
Mã:
headers: { "x-auth-token": localStorage.getItem("token")}
Lấy dữ liệu bằng Hook useRouter
Trong phần đầu tiên, chúng ta đã thấy quy trình lấy dữ liệu động hoạt động như thế nào trong Next.js đối với một ứng dụng không yêu cầu xác thực.Trong phần này, chúng ta sẽ xem cách bỏ qua sự cố của các phương thức lấy dữ liệu
getStaticProps
và getStaticPaths
gây ra referenceError
(“localStorage
is undefined”) khi chúng ta cố gắng lấy mã thông báo của người dùng từ localStorage
.Lỗi này xảy ra vì hai phương thức lấy dữ liệu luôn chạy trên máy chủ ở chế độ nền, do đó, đối tượng
localStorage
không khả dụng đối với chúng vì đối tượng này nằm ở phía máy khách (trong trình duyệt).API bộ định tuyến của Next.js tạo ra nhiều khả năng khi chúng ta xử lý các tuyến động và dữ liệu. Với hook
useRouter
, chúng ta có thể lấy dữ liệu duy nhất cho người dùng dựa trên ID duy nhất của họ.Hãy xem đoạn trích bên dưới để bắt đầu:
Mã:
// pages/index.jsimport React from "react";import axios from "axios";import { userEndpoints } from "../../../routes/endpoints";import Link from "next/link";const Users = () => { const [data, setData] = React.useState([]) const [loading, setLoading] = React.useState(false) const getAllUsers = async () => { try { setLoading(true); const response = await axios({ phương thức: "GET", url: userEndpoints.getUsers, tiêu đề: { "x-auth-token": localStorage.getItem("token"), "Content-Type": "application/json", }, }); const { dữ liệu } = phản hồi.dữ liệu; setData(dữ liệu); } catch (lỗi) { setLoading(false); console.log(lỗi); } }; return (
Danh sách người dùng
{data.map((user) = > { return (
[*]
{user.name}
{user.role}
); })} );};export default Users;
useEffect
để lấy dữ liệu sau khi trang được hiển thị lần đầu tiên. Bạn cũng sẽ nhận thấy rằng JWT được gán cho khóa x-auth-token
trong tiêu đề yêu cầu.Khi chúng ta nhấp vào một người dùng, thành phần
Link
sẽ định tuyến chúng ta đến một trang mới dựa trên ID duy nhất của người dùng đó. Khi chúng ta ở trên trang đó, chúng ta muốn hiển thị thông tin có sẵn cụ thể cho người dùng đó với id
.Móc
useRouter
cho phép chúng ta truy cập vào pathname
trong tab URL của trình duyệt. Với điều đó, chúng ta có thể lấy tham số truy vấn của tuyến đường duy nhất đó, đó là id
.Đoạn trích dưới đây minh họa toàn bộ quá trình:
Mã:
// [id].jsimport React from "react";import Head from "next/head";import axios from "axios";import { userEndpoints } from "../../../routes/endpoints";import { useRouter } from "next/router";const UniqueUser = () => { const [user, setUser] = React.useState({ fullName: "", email: "", role: "", }); const [loading, setLoading] = React.useState(false); const { query } = useRouter(); // Lấy ID duy nhất của người dùng bằng Next.js' // useRouter hook. const currentUserId = query.id; const getUniqueUser = async () => { try { setLoading(true); const response = await axios({ method: "GET", url: `${userEndpoints.getUsers}/${currentUserId}`, headers: { "Content-Type": "application/json", "x-auth-token": localStorage.getItem("token"), }, }); const { data } = response.data; setUser(data); } catch(lỗi) { setLoading(false); console.log(lỗi); } }; React.useEffect(() => { getUniqueUser(); }, []); trả về ( {`${user.fullName}'s Profile | "Profile" `}
{user.fullName}
{user.role}
{user.email}
)} );};export default UniqueUser;
useRouter
, hook mà chúng tôi sẽ sử dụng để lấy ID duy nhất của người dùng và truyền nó làm đối số cho điểm cuối API.
Mã:
const {query} = useRouter()const userId = query.id
Kết luận
Việc lấy dữ liệu trong Next.js có thể trở nên phức tạp nếu bạn không hiểu đầy đủ về trường hợp sử dụng của ứng dụng.Tôi hy vọng bài viết này đã giúp bạn hiểu cách sử dụng API bộ định tuyến của Next.js để lấy dữ liệu động trong ứng dụng của mình.
Đọc thêm
- Quốc tế hóa trong Next.js 13 với các thành phần React Server
- Tạo biểu mẫu nhiều bước hiệu quả để có trải nghiệm người dùng tốt hơn
- Cách OWASP giúp bạn bảo mật các ứng dụng web đầy đủ của mình
- Tích hợp: Từ truyền dữ liệu đơn giản đến kiến trúc có thể cấu hình hiện đại