Nested layout với Nextjs
Bài đăng này đã không được cập nhật trong 4 năm
Xin chào các bạn, lại là mình với câu chào cũ rích. Dạo gần đây mình đang tìm hiểu về Nextjs
, nên hôm nay mình sẽ chia sẻ một chút về nested layout
trong Nextjs
vậy.
Thì trước khi tìm hiểu về nested layout, thì chúng ta hãy cùng đi giải thích về Router
trong Nextjs
đã. Trong Nextjs
, thì việc quản lý router
đều liên quan đến thư mục pages
, khi chạy dòng lệnh cài đặt Nextjs
, thì tất cả mọi thứ đều đã được cài đặt, việc của chúng ta chỉ là cài đặt và chạy mà thôi.
npx create-next-app nextjs-blog
Sau khi cài đặt và khởi chạy, bạn sẽ thấy thư mục page
s trong source code
của mình, hãy lưu ý đến nó, khác với React router
, Nextjs
quản lý router
của bạn bằng thư mục, ví dụ:
- Bạn muốn một trang
about
để giới thiệu về trang web của mình ? => Thêmabout.js
vào trong thư mụcpages
- Bạn muốn một trang
service
để giới thiệu về những dịch vụ mà trang web bạn cung cấp ? => Thêmservice.js
vào thư mụcpages
- Bạn có một trang
blog
, nhưng trongblog
lại có nhiều bàipost
nhưfirst-post
,second-post
=> Tạo thư mụcblog
chứa 2 filefirst-post.js
,second-post
, sau đó đưa thư mụcblog
và trong thư mụcpages
Mọi thứ trông có vẻ thật đơn giản nhỉ, mình sẽ tổng hợp một bảng để bạn dễ dàng so sánh hơn:
Type | Folder | Url |
---|---|---|
Index routes | pages/index.js |
/ |
pages/blog/index.js |
/blog |
|
Nested routes | pages/blog/first-post.js |
/blog/first-post |
pages/dashboard/settings/username.js |
/dashboard/settings/username |
|
Dynamic route segments | pages/blog/[slug].js |
/blog/:slug (/blog/hello-world) |
pages/[username]/settings.js |
/:username/settings (/foo/settings) |
|
pages/post/[...all].js |
/post/* (/post/2020/id/title) |
Ơ, thế Router
thì liên quan gì đến NestedLayout
đâu nhỉ ?
Thật ra thì Router
còn thiếu một thứ mình chưa nhắc tới, đó là mình muốn tạo một trang có header thì phải làm như thế nào ?
Router
trong Nextjs
không hỗ trợ trực tiếp cho ta giống như React router
, mà phải :code:
bằng "cơm" - thực ra thì cái nào cũng bằng cơm cả Thì bây giờ mình sẽ hướng dẫn từng bước một nhé.
Trước tiên mình cần thêm defaultLayout
, được dùng để fallback
khi mà một trang nào đó không cần sử dụng header
bên trên.
import React from 'react';
export default DefaultLayout = ({ children }) => <>{children}</>;
Rồi tiếp theo mình cần thêm một layout nữa, có header
- cái mà chúng ta cần:
import Link from 'next/link';
const DocsLayout = ({ children }) => (
<div className="docs-container">
<div className="header">
<h3>Docs</h3>
<p>This is doc layout</p>
</div>
<div className="main">{children}</div>
</div>
);
export default DocsLayout;
Rồi tiếp theo mình cần thêm một component để hiển thị blog
nữa
import DocsLayout from '../components/layout/doc';
const Doc = () => (
<div className="docs">
<h1>Page 1</h1>
<p>...</p>
</div>
);
Doc.Layout = DocsLayout;
export default Doc;
Sau đó, chúng ta cần override lại App
của Nextjs
, mình cần tạo file _app.js
bên trong pages
// pages/_app.js
import React from 'react';
import App from 'next/app';
import DefaultLayout from '../components/layout';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
const Layout = Component.Layout || DefaultLayout;
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
}
export default MyApp;
Bạn có thấy thắc mắc chỗ nào không, mình nghĩ là có đó:
//doc.js
Doc.Layout = DocsLayout;
//_app.js
const Layout = Component.Layout || DefaultLayout;
Tại sao mình lại cần hai cái này nhỉ, để mình giải thích nhé.
- Một
component
trongReact
đều làObject
, việc mình gánDoc.Layout = DocsLayout;
vào componentdoc
là để tạo mộtkey: value
bên trong component đó, lúc đó object sẽ tương tự như thế này:const Doc = { ... Layout: DocsLayout }
- Việc mình thêm điều kiện ở
_app.js
là để kiểm tra xem, bên trong mộtcomponent
đượcrender
ra trang web có chứakey
làLayout
hay không, nếu có hãy lấyLayou
t đó ra làmlayout
bao bọc bên ngoàicomponent
. Còn nếu không, thì hãy sử dụngDefaultLayout
mà mình đã khởi tạo bên trên vào.
Logic của chúng ta chỉ có thế, vì Viblo không thể embed được link codesanbox, nên mình sẽ để link ở đây cho bạn tìm hiểu nhé Cảm ơn các bạn đã đọc bài của mình
All rights reserved