Một số vấn đề với NEXTJS
Lấy 200$ cloud miễn phí để tha hồ deploy project và nghịch phá server ở đây nhé mọi người.
👇️👇️👇️
NEXTJS
NextJs là một framework nhỏ gọn giúp bạn có thể xây dựng ứng dụng Single Page App - Server Side Rendering với ReactJs một cách dễ dàng. Thực sự NextJs khá dễ tiếp cập, chúng ta chỉ cần có chút xíu kiến thức về React/Redux
và Nodejs/Express
thì chỉ cần bỏ ra thêm vài giờ là có thể sử dụng NextJs
cơ bản được rồi.
Nên mình viết bài này, hy vọng có thể chia sẻ một số vấn đề nhỏ mình mắc phải khi sử dụng NextJs, mà mò ở trang documents mãi không thấy, chứ không đi vào tìm hiểu cũng như demo các ví dụ mà trên documents của Nextjs đã có.
(Update, vài điểm bài viết tại thời điểm viết bài cho đến hiện tại có thể không còn chính xác nữa, vì gần đây nextjs đã update lại khá nhiều so với thời điểm mình viết bài. Ví dụ như phần custom title bar. Hiện next đã hỗ trợ việc này rất dễ dàng với một built-in component head
...v.vv)
Cài đặt NextJs bằng create-next-app
Việc cài đặt NextJs tương đối đơn giản. Bạn có thể tìm thấy ở trang chủ của NextJs cách cài đặt một NextJs project căn bản. Tuy nhiên cách này khá "thủ công", nên mình thích sử dụng Create Next App
hơn. Bởi cách này cũng giống như khi sử dụng Create React App
để tạo một React project vậy. Tiện dụng hơn, được xây dựng sẵn cấu trúc thư mục cơ bản và an toàn hơn nữa.
Bạn cài đặt create-next-app
ở chế độ global
và sau đó sử dụng create-next-app
để tạo một project mới tên là viblo-demo
như dưới đây:
npm install -g create-next-app
create-next-app viblo-demo
Ta được một project mới với cấu trúc thư mục như thế này: Sau đó start project của chúng ta lên
cd vibo-demo/
npm run dev
Sau đó truy cập vào localhost cổng 3000 bạn sẽ thấy trang Welcome to Next!
.
Tạo trang và điều hướng giữa các trang
- Như vậy là ta đã có được một ứng dụng NextJs cơ bản. Như trong cấu trúc thư mục ở trên. Thư mục
pages
sẽ là nơi chứa các trang chính của ứng dụng. Ví dụ như trên có trang index.
Nếu bạn muốn tạo thêm trangabout
chẳng hạn. Thì ta tạo thêm fileabout.js
trong folderpages
. Với mình, thì khi làm việc với project react. Mình hay tạo mội folder tên làcontainers
trong đó chứa các components lớn - thường là các trang của ứng dụng nhưdetails
,shoppingCart
..v.v..
Hiểu nôm na thì folder pages này cũng đóng vai trò tương tự như foldercontainers
như khi làm việc với react thông thường của mình vậy. Bây giờ ta hãy tạo một một fileabout.js
tương ứng với trangabout
nhé. Với nội dung như dưới đây
export default () => (
<div>
<p>This is the about page</p>
</div>
)
Truy cập vào địa chỉ localhost:3000/about
ta nhận được trang about với dòng chữ dòng chữ This is the about page
- Để điều hướng giữa các trang. Ở React ta sử dụng
react-router-dom
còn với NextJs ta sử dụngnext/link
. Thay thế nội dung trong fileindex.js
như dưới đây:
import Link from 'next/link'
const Index = () => (
<div>
<Link href="/about">
<a>About Page</a>
</Link>
<p>Hello Next.js</p>
</div>
)
export default Index
Truy cập vào trang chủ và nhấn vào link About Page
Ta được chuyển đến trang about mà hoàn toàn không load lại trang ( hiển nhiên rồi )
Ở ví dụ trên, ta sử dụng Link API
một API của next/link
của NextJs, nó khá giống với Link
của react-router-dom
nhỉ ?
// react-router-dom
<Link to="/about">
About Page
</Link>
// next/link
<Link href="/about">
<a>About Page</a>
</Link>
Vấn đề với Custom Styling Components
Bạn có thể tham khảo thêm tại đây. Mặc định, NextJs bắt chúng ta phải viết Css
cho componets kiểu thế này:
export default () => (
<div>
<p>This is the about page</p>
<style jsx>{`
p, a {
font-family: "Arial";
}
`}
</div>
)
Trông phát khiếp lên được, nhất là đối với một người kỹ năng css không được tốt như mình. Với cả, mình quen viết css kiểu này hơn.
import 'classes' from './about.css'
export default () => (
<div>
<p className={ classes.Ptag } >This is the about page</p>
</div>
)
Để viết được css kiểu này bạn cần cài thêm một plugin tên là zeit/next-css
:
npm install --save @zeit/next-css
# Hoặc cài bằng yarn
yarn add @zeit/next-css
Sau đó, bạn cần tạo thêm một file tên là next.config.js
ở ngay ngoài thư mục gốc của project với nội dung như sau:
const withCSS = require('@zeit/next-css')
module.exports = withCSS()
Cuối cùng bạn tạo thêm một file tên là _document.js
trong folder pages
với nội dung như dưới đây:
import Document, { Head, Main, NextScript } from 'next/document'
import classes from './app.css';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<html>
<Head>
<link rel="stylesheet" href="/_next/static/style.css" />
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
Chạy lại npm run dev
. Thì khi đó chúng ta mới có thể viết css theo kiểu import
như trên được.
Làm thế nào để sử dụng Redux
Trên trang chủ documents của Nextjs cũng không có hướnng dẫn phần này. Nghĩa là chỉ hướng dẫn chúng ta sử dụng next với React "thuần". Trong khi mình lại muốn sử dụng Redux
và ImmutableJs
.
Nên sau một hồi tự cài redux-thunk
các thứ không được - Vì Nextjs thiết lập state ở cả client và server nên không thể npm install
rồi sử dụng như cách mình vẫn làm được.
Google trong đau khổ một lúc, mình mới phát hiện ra một điểm thú vị, rằng tuy documents chính không nhắc đến, nhưng trang Github của Nextjs lại chứa những phần ví dụ khá đầy đủ. Bạn có thể truy cập vào phần examples trên trang github của Nextjs. Trong đó có sẵn rất nhiều project mẫu đủ mọi thứ chúng ta cần. Từ ví dụ hello-world
đến sử dụng NextJs với material-ui
, redux-thunk
, redux-saga
..v.v. Đều có cả
bây giờ, ta hãy tạo thử một project NextJs khác với redux thunk
nhé
npx create-next-app --example with-redux viblo-demo-with-redux
# Hoặc
yarn create next-app --example with-redux viblo-demo-with-redux
Trong đó, tham số --example
để create-next-app
tạo sẵn cho chúng ta một vài components ví dụ mẫu. Tiện theo đó mà tham khảo.
Ta thu được project folder như hình dưới
Trong đó đã đính kèm ba components mẫu, trong folder components như trên hình gồm clock.js
, couter.js
, example.js
Chỉ cần xem qua những file này là có thể làm được. Bởi cách dùng redux-thunk
với NextJs
cũng tương tự như khi sử dụng thông thường chỉ khác mỗi component có thêm hàm để lấy staste từ server nếu request đến là first request
- tức lần request đầu tiên người mà dùng truy cập vào ứng dụng của chúng ta. Thực ra cũng không cần quan tâm lắm. ( Có lẽ khi ứng dụng của mình phức tạp hơn thì mình cần mổ xẻ cái này đấy - chỉ là hiện tại mình chưa gặp vấn đề gì liên quan đến nó thôi. Dễ là như thế lắm )
static getInitialProps ({ reduxStore, req }) {
const isServer = !!req
reduxStore.dispatch(serverRenderClock(isServer))
return {}
}
Làm sao để sử dụng immutablejs
Để sử dụng redux-thunk và immutable trong NextJs
ta tạo một project như sau
npx create-next-app --example with-immutable-redux-wrapper vibo-demo-with-immutable-redux-wrapper
# or
yarn create next-app --example with-immutable-redux-wrapper vibo-demo-with-immutable-redux-wrapper
Ta cũng sẽ thu được một project với một số components mẫu đi kèm, miễn là bạn có kinh nghiệm sử dụng React thì nhìn qua là hiểu liền hà.
Lưu ý là state
của ứng dụng được lưu trong file store.js
ngay ngoài thư mục gốc, trong đó đã bao gồm cả actions
, reducers
và state
của ứng dụng. Nếu muốn cấu trúc lại, bạn chỉ cần vào sửa file _app.js
là được.
Làm sao để custom title trên tab bar
Điều này có thể không cần thiết lắm, nhưng nó thực sự khiến mình khó chịu. Mặc định NextJs sẽ hiển thị tab bar trên chrome như thế này.
Nên muốn thêm icon hay đổi title ta phải tạo thêm một file tên là _document.js
như ở phần Vấn đề với Styling Components
ở trên:
import Document, { Head, Main, NextScript } from 'next/document'
import classes from './app.css';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<html>
<Head>
<title>Viblo is awesome</title>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="/_next/static/style.css" />
</Head>
<body className="is-preload" id="is-body">
<Main />
<NextScript />
</body>
</html>
)
}
}
Kết luận
Thực sự thì để giới thiệu hết thì rất dài, hơn nữa mình mới làm quen với NextJs
qua một project nhỏ xíu và kinh nghiệm React
cũng chưa có nhiều, nên cũng không có nhiều điều để viết. Còn những vấn đề như server router, làm đẹp url, lấy giá trị từ query string hay lazy loading..v.v. những cái đó có sẵn trên document. Bạn có thể xem qua một chút nhé. Cám ơn bạn đã dành thời gian cho bài viết của mình...
All rights reserved