Loading Routes trong React
Là một developer, khi chúng ta build app cho user trên internet, điều quan trọng nhất là bảo đảm tốc độ xử lí và phục vụ cho người dùng vẫn nhanh nhất có thể.
Khi build một React app, ta thường hay bắt gặp việc kích thước của ứng dụng bị tăng lên nhanh chóng bởi số lượng dependencies được sử dụng. Nó xảy ra khi một phần của app (hoặc route) có thể đã import một lượng lớn các components không cần thiết khi nó mới load lần đầu tiên, dẫn tới việc tăng thời gian load của app.
Vậy làm sao để chúng ta tiếp cận vấn đề này? Liệu có cách nào để chỉ load những thứ cần thiết và tránh một đống code thừa thãi?
Chúng ta có thể đạt điều đó nhờ vào Lazy Loading. Nó là một cách thức rất hay để tối ưu hóa website của bạn, nó thực hiện điều đó bằng cách chia code của bạn tại những điểm breakpoints, và sau đó load khi user tương tác và cần tới một đoạn code mới. Giúp cho tăng tốc độ load cho app cũng như rút bớt kích thước của ứng dụng do có nhiều đoạn code không hề được load.
Trong React, chúng ta lazy load components và routes bằng cách chia cắt code nhờ vào Webpack. Khi chia app của bạn thành những phần nhỏ và chỉ load những thứ cần cho page render.
Vậy thì hãy thử một React app thật đơn giản và xem thử cách chúng ta có thể lazy load routes.
Bootstrap một React app với create-react-app
Chúng ta sẽ sử dụng create-react-app CLI để bootstrap một React app mới. CLI, vốn được build bởi Facebook giúp developer bằng cách tạo ra một React app hoạt động trơn tru mà không cần bất cứ build configuration nào.
Cái đặt create-react-app tool với command sau:
npm install -g create-react-app
Sau khi qua trình cài đặt đã xong, bạn giờ đây đã có thể tạo một React app bằng command create-react-app lazy-loading-routes
Nó sẽ tạo ra một new folder với tất cả file cần để chạy React app. Bạn giờ đã có thể đã có thể chạy mọi commands sau:
npm start npm run build npm test
npm start
command chạy app trong development mode, command npm run build
sẽ build app trong folder build
, và npm test
command sẽ chạy test watcher trong interactive mode.
React app mà chúng ta build sẽ có routes/components sử dụng một hoặc hai React plugins.
Thiếu code splitting, toàn bộ React code và plugins sẽ bị bundled vào thành một JavaScript file, nhưng với code splitting, chỉ component/plugin sẽ cần để load.
Quay trở về việc build một app, create-react-app
CLI sẽ tạo ra một React app như đã nói trên và cho phép chúng ta bắt đầu build ngay lập tức.
Trước hết, hãy set up những routes đơn giản chúng ta sẽ cần tới cho React app. Cho routing, chúng ta sẽ sử dụng react-router. bạn có thể thêm react-router package vào app bằngnpm install react-router-dom
trong terminal.
Sau khi quá trình cài đặt đã hoàn thành, chúng ta có thể bắt đầu với việc tạo những components, vốn sẽ đóng vai trò như các routes. Cho app này, chúng ta sẽ dùng 4 routes; Home
, Maps
, Blog
và một route dành cho 404 page NotFound
.
Vào folder src
trong project directory và chạy commands sau:
mkdir Home Maps Blog NotFound
Nó sẽ tạo folder cho nhiều components khác nhau để có thể dùng về sau. Đây là một cách phân chia React app.
Trước khi chúng ta tạo components, hãy edit App.js file và set up các route đơn giản trước. Mở App.js
file và edit những dòng code sau:
// Import React and Component import React, { Component } from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom' // Import the Home component to be used below import Home from './Home/Home' // Import the Maps component to be used below import Maps from './Maps/Maps' // Import the Blogs component to be used below import Blog from './Blog/Blog' // Import the NotFound component to be used below import NotFound from './NotFound/NotFound' // Import CSS from App.css import './App.css'; import createBrowserHistory from 'history/createBrowserHistory'; const history = createBrowserHistory(); class App extends Component { render () { return ( <Router history={history}> <div> <header className="header"> <nav className="navbar container"> <div className="navbar-brand"> <Link to="/"> <span className="navbar-item">Lazy Loading Routes</span> </Link> </div> <div className="navbar-end"> <Link to="/maps"> <span className="navbar-item">Maps</span> </Link> <Link to="/blog"> <span className="navbar-item">Blog</span> </Link> </div> </nav> </header> <section className="content"> <Switch> <Route exact path="/" component={Home} /> <Route path="/maps" component={Maps} /> <Route path="/blog" component={Blog} /> <Route path="*" component={NotFound} /> </Switch> </section> </div> </Router> ) } } export default App;
Trong dòng code trên, chúng ta imported React và Component module của nó bằng ES6 import, đồng thời bạn cũng cần BrowserRouter
, Route
, Switch
và Link
từ react-router
. Trong render()
function, đầu tiên ta sẽ tạo ra view cho user dùng để navigate các route khác nhau và sau đó <Switch>
component sẽ giữ những routes khác cũng như component phản ứng đến chúng.
App.css
file nên được edit với dòng code sau:
Hãy tiếp tục với components, vào Home
folder và tạo ra những file sau: Home.js
và Home.css
. Mở Home.js
file và edit những dòng code sau:
import React, { Component } from 'react' import './Home.css' import Button from '../NavButton/NavButton' class Home extends Component { render () { return ( <div className="container"> <section className="section"> <div className="container"> <h1 className="title">Lazy Loading</h1> <h2 className="subtitle"> A simple app to demonstrate how lazy loading routes in React works. </h2> <section className="bottom"> <Button name="Go to About page" link="/about" /> <Button name="Go to Blog page" link="/blog" /> </section> </div> </section> </div> ) } } export default Home
Trong đoạn mã trên, chúng ta đơn giản là tạo ra view cho Home component. Một Button
component được dùng, nó lấy prop
của name
và link
. Chúng ta cũng import style từ Home.css
file. Hãy thử viết CSS cho file.
Tiếp theo là Maps route, bạn có thể hiểu map page sẽ đơn giản là hiển thị Google map của một vị trí sử dụng google-map-react React plugin. Vào Maps
folder và tạo những files tiếp theo: Maps.js
và Maps.css
. Mở Maps.js
file và edit những code sau:
import React, { Component } from 'react' import './Maps.css' import GoogleMapReact from 'google-map-react'; const MapsView = ({ text }) => ( <div style={{ position: 'relative', color: 'white', background: 'red', height: 40, width: 60, top: -20, left: -30, textAlign: 'center', paddingTop: '5px' }}> {text} </div> ); class Maps extends Component { static defaultProps = { center: {lat: 6.5244, lng: 3.3792}, zoom: 11 }; render () { return ( <div className="container"> <p>This page is simply a page that shows a Google Map view of a location. Play around with the coordinates to get a different view</p> <div className="map-container"> <GoogleMapReact defaultCenter={this.props.center} defaultZoom={this.props.zoom} > <MapsView lat={6.5244} lng={3.3792} text={'Your Location'} /> </GoogleMapReact> </div> </div> ) } } export default Maps
Trong những code trên, đầu tiên ta import React
, và Component module của nó. google-map-react
plugin cũng sẽ được import. MapsView()
function lấy tham số của text
và để nó vào trong một div
.
Kế tiếp, ta có ES6 class tên làMaps
với khả năng mở rộng component module từ react
. Trong Maps
component, ta set giá trị props
bằng cách sử dụng object defaultProps
và render()
function chứa view và GoogleMapReact
component. Nếu bạn muốn đọc thêm về plugin google-map-react
bạn có thể vào đây xem.
Hãy thử viết CSS cho Maps.css
file. Mở file và viết code như sau:
Component tiếp theo là Blog component, vốn dùng một React plugin gọi là react-markdown để render markdown vào trong các pure React component. Mở Blog
folder và tạo Blog.js
file. Mở Blog.js
file và edit như sau:
import React, { Component } from 'react' import ReactMarkdown from 'react-markdown' class Blog extends Component { constructor(props) { super(props); this.state = { markdownSrc: [ '# Lazy Loading Routes with React\n\nWhy do we need to lazy load routes?.\n\n* Reduce code bloat\n* Avoid loading all components at the same time ', '\n* React app loads faster', '\n* Load only the component that is needed and preload the others\n', '\n## A quote\n\n<blockquote>\n A man who splits his code ', 'is a wise man.\n</blockquote>\n\n## How about some code?\n', '```js\nimport React, { Component } from \'react\';\nimport asyncComponent from \'./AsyncComponent\'', '\n\nimport {\n' + ' BrowserRouter as Router,\n' + ' Route,\n' + ' Switch,\n' + ' Link\n' + '} from \'react-router-dom\'\n```\n\n\n' ].join(''), htmlMode: 'raw' }; } render () { return ( <div className="container"> <ReactMarkdown source={this.state.markdownSrc} /> </div> ) } } export default Blog
Trong đoạn code trên, ta sẽ imported react-markdown plugin và dùng nó để render markdown trong state.markdownSrc
vào pure React component trong render()
function.
Component cuối cùng là NotFound
route, vào NotFound
folder và tạo NotFound.js
file. Mở NotFound.js
file và edit đoạn code sau:
Ta dùng Button
component trong Home
route trên, và tạo ra một component mới. Trong src
folder, tạo một folder với tên là NavButton
, sau đó tạo một file NavButton.js
trong folder đó. Mở NavButton.js
file và edit như sau:
Trong code trên, ta đã tạo một functional stateless component để tạo view cho một nút. Component là một nút có chức năng giúp navigation trong React app, đạt được điều này là nhờ vào react-router
, vốn được import trên top của file. Button
component nhận vào hai props
; link
và name
. link
prop được dùng để xác định route nào để navigate, và name
prop được dùng để hiển thị đoạn text trong button.
Bây giờ thì bạn đã có thể chạy app để xem tiến triển của mình. Để xem app trong development mode, hãy dùng command npm start
trong terminal của bạn và sẽ thấy một homepage tương tự như sau:
Giờ thì ta đã biết app chạy tốt, hãy thử phân tích và xem app load toàn bộ JavaScript code mà chúng ta đã viết ra như thế nào. Chạy command npm run build
trong terminal để build app:
Bạn có thể thấy toàn bộ JavaScript code đều được nằm trong một file main.....js
với kích thước khá nhỏ. Nhưng nếu ta tăng qui mô của app lên thì điều này sẽ cực kì rắc rối bởi kích thước của chúng cũng tăng lên chóng mặt. Do đó ta sẽ dùng tới code splitting.
Code Splitting
Đây chính là lí do vì sao mà ta trải qua mọi thứ. Làm cách nào để áp dụng code splitting trong React app? Đó là nhờ vào Webpack và bởi vì create-react-app
đã được ship với Webpack, ta sẽ cần thêm config hay eject create-react-app
.
Hãy thử xem routes setup mà chúng ta đã defined ở trên:
Với setup như vậy, Switch
component sẽ render route phù hợp với path mà users navigate thông qua component trên. Vì ta đã import tất cả các component, điều đó có nghĩa là chúng đều sẽ load khi user đến một route nhất định, bao gồm cả những component không cần thiết.
Đó là lúc code splitting tỏa sáng. Code splitting giúp import components và chỉ load chúng khi cần và nhờ đó loại trừ những JavaScript code không cần thiết. Vậy làm cách nào để dùng nó?
Tạo một file tên là AsyncComponent.js
trong src
folder và edit như sau:
asyncComponent()
function chọn một tham số, , getComponent
vốn là một function sẽ import một component được cho sẵn. Nó sẽ không được called cho đến khi mount lần đầu tiên. Trên componentWillMount
, ta sẽ đơn giản call getComponent
function được pass và lưu loaded component trong state. Cuối cùng, ta render component nếu nó đã load hoàn toàn, còn không thì ta đơn giản render null.
Giờ đã xong asyncComponent
, hãy thay đổi cách import component trong App.js
file bằng cách import chúng asyncComponent()
function. Đoạn code dưới đây trong App.js file sẽ được thay bằng đoạn thứ 2 nếu bạn làm đúng.
Như vậy, kết quả cuối cùng của App.js
sẽ trông như thế này:
import React, { Component } from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom' import NotFound from './NotFound/NotFound' import './App.css'; import createBrowserHistory from 'history/createBrowserHistory'; import asyncComponent from './AsyncComponent' const Home = asyncComponent(() => import('./Home/Home').then(module => module.default) ) const Maps = asyncComponent(() => import('./Maps/Maps').then(module => module.default) ) const Blog = asyncComponent(() => import('./Blog/Blog').then(module => module.default) ) const history = createBrowserHistory(); class App extends Component { render () { return ( <Router history={history}> <div> <header className="header"> <nav className="navbar container"> <div className="navbar-brand"> <Link to="/"> <span className="navbar-item">Lazy Loading Routes</span> </Link> </div> <div className="navbar-end"> <Link to="/maps"> <span className="navbar-item">Maps</span> </Link> <Link to="/blog"> <span className="navbar-item">Blog</span> </Link> </div> </nav> </header> <section className="content"> <Switch> <Route exact path="/" component={Home} /> <Route path="/maps" component={Maps} /> <Route path="/blog" component={Blog} /> <Route path="*" component={NotFound} /> </Switch> </section> </div> </Router> ) } } export default App;
Xin chúc mừng, bạn đã áp dụng thành công code splitting, hãy thử thực hiện một số phân tích và xem app chạy như thế nào bằng command npm run build
:
Bạn có thể thấy rằng code đã được chia thành nhiều phần khác nhau , và giờ React sẽ chỉ load những component cần cho path thay vì load mọi thứ.
Lời kết
Code splitting giúp cho việc code không bị phình bự lên. Nếu bạn muốn nhanh hơn nữa thì có thể dùng react-loadableplugin. Nó là một component cao cấp với khả năng load component với promise.
Nguồn: TopDev via scotch
Tham khảo các vị trí việc làm React hấp dẫn
- G Giải Quyết Bài Toán Kinh Doanh Bằng Big Data và AI
- B BenQ RD Series – Dòng Màn Hình Lập Trình 4k+ Đầu Tiên Trên Thế Giới
- F Framework nào tốt nhất cho dự án của bạn? – Checklist chi tiết
- K Kinh nghiệm xử lý responsive table hiệu quả
- S Stackoverflow là gì? Bí kíp tận dụng Stack Overflow hiệu quả
- 7 7 kinh nghiệm hữu ích khi làm việc với GIT trong dự án
- B Bài tập Python từ cơ bản đến nâng cao (có lời giải)
- B Bảo mật API là gì? Một số nguyên tắc và kỹ thuật cần biết
- H Hướng dẫn cài đặt và tự học lập trình Python cơ bản từ A-Z
- C Chinh Phục Phân Tích Dữ Liệu Với Pandas Trong Python: Hướng Dẫn Từng Bước