├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.css ├── App.js ├── index.css └── index.js └── virtual-scroll.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Virtual Scroll Sample (React virtualized) 2 | 3 | Như chúng ta đã biết khi trình duyệt web tải một lượng dữ liệu xuống để hiển thị (ví dụ 10000 bản ghi) sẽ rất chậm, đơ, hiệu năng thấp ảnh hưởng tới khá nhiều trải nghiệm người dùng (UX). 4 | 5 | Chính vì thế là người ta đã sinh ra phương pháp cải thiện đó là virtual scroll, chỉ render những phần trong view point (khung nhìn) của người dùng. Thay vì hiển thị hết 10000 phần tử HTML thì chỉ cần hiển thị hơn chục phần tử. 6 | 7 | Khi ta cuộn thì 1 số phần tử sẽ bị loại khỏi DOM để tối ưu và thanh cuộn sinh ra là thanh cuộn ảo. Như thế cho dù chúng ta có hiển thị nhiều dữ liệu như nào đi nữa ứng dụng vẫn sẽ mượt mà :)) 8 | 9 | 10 | Ảnh minh họa: 11 | 12 | ![Virtual Scroll](./virtual-scroll.gif) 13 | 14 | ## CÀI ĐẶT 15 | 16 | npm install 17 | 18 | ## SỬ DỤNG 19 | 20 | npm start 21 | 22 | Đoạn code ví dụ sử dụng react virtualized hiển thị list danh sách lên đến 10000 phần tử: 23 | 24 | ```javascript 25 | const rowCount = 10000; 26 | const rowHeight = 50; 27 | const listHeight = 500; 28 | 29 | const App = () => { 30 | const list = Array(rowCount) 31 | .fill() 32 | .map((val, idx) => { 33 | return { 34 | id: idx, 35 | image: "http://via.placeholder.com/40", 36 | text: loremIpsum({ 37 | count: 1, 38 | units: "sentences", 39 | sentenceLowerBound: 4, 40 | sentenceUpperBound: 8, 41 | }), 42 | }; 43 | }); 44 | 45 | const renderRow = ({ index, key, style }) => { 46 | return ( 47 |
48 |
49 | 50 |
51 |
52 |
ID: {list[index].id}
53 |
{list[index].text}
54 |
55 |
56 | ); 57 | }; 58 | 59 | return ( 60 |
61 | 62 | {() => { 63 | return ( 64 |
65 |
66 | 75 |
76 |
77 | ); 78 | }} 79 |
80 |
81 | ); 82 | }; 83 | export default App; 84 | 85 | ``` 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-virtualized-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.14.0", 7 | "react-dom": "^16.14.0", 8 | "react-scripts": "4.0.3", 9 | "web-vitals": "^2.1.4" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build" 14 | }, 15 | "eslintConfig": { 16 | "extends": [ 17 | "react-app", 18 | "react-app/jest" 19 | ] 20 | }, 21 | "browserslist": { 22 | "production": [ 23 | ">0.2%", 24 | "not dead", 25 | "not op_mini all" 26 | ], 27 | "development": [ 28 | "last 1 chrome version", 29 | "last 1 firefox version", 30 | "last 1 safari version" 31 | ] 32 | }, 33 | "devDependencies": { 34 | "lorem-ipsum": "^2.0.8", 35 | "react-virtualized": "^9.22.3" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chungred/react-virtualized-example/35d5939584f8c64e8a281b6d828f4884a6e781ad/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | React App 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: block; 3 | margin: 0 auto; 4 | } 5 | 6 | .row-list { 7 | display: flex; 8 | align-items: center; 9 | } 10 | 11 | .row-list:nth-child(2n + 1) { 12 | background: #eee; 13 | } 14 | 15 | .image { 16 | display: flex; 17 | align-items: center; 18 | } 19 | 20 | .content { 21 | padding-left: 5px; 22 | } 23 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./App.css"; 3 | import { loremIpsum } from "lorem-ipsum"; 4 | import { List, AutoSizer } from "react-virtualized"; 5 | 6 | const rowCount = 10000; 7 | const rowHeight = 50; 8 | const listHeight = 500; 9 | 10 | const App = () => { 11 | const list = Array(rowCount) 12 | .fill() 13 | .map((val, idx) => { 14 | return { 15 | id: idx, 16 | image: "http://via.placeholder.com/40", 17 | text: loremIpsum({ 18 | count: 1, 19 | units: "sentences", 20 | sentenceLowerBound: 4, 21 | sentenceUpperBound: 8, 22 | }), 23 | }; 24 | }); 25 | 26 | const renderRow = ({ index, key, style }) => { 27 | return ( 28 |
29 |
30 | 31 |
32 |
33 |
ID: {list[index].id}
34 |
{list[index].text}
35 |
36 |
37 | ); 38 | }; 39 | 40 | return ( 41 |
42 | 43 | {() => { 44 | return ( 45 |
46 |
47 | 56 |
57 |
58 | ); 59 | }} 60 |
61 |
62 | ); 63 | }; 64 | export default App; 65 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); -------------------------------------------------------------------------------- /virtual-scroll.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chungred/react-virtualized-example/35d5939584f8c64e8a281b6d828f4884a6e781ad/virtual-scroll.gif --------------------------------------------------------------------------------