This article directly about actual combat, not virtual, source code, there is a display. If the back end throws you 100,000 pieces of data, how do you show??

No more words and direct results.

We will show him how large the page is on the home page. All the operations behind it can be monitored, so it is ok to show the corresponding data after the operation behavior in the monitoring process.

In line with the principle of visual presentation.

It is to display the data within the limited visual range of the screen, and then display the corresponding operation behavior through the monitoring events of the table, such as scroll bar, mouse scroll, drag and so on.

Preview the address

Tcly861204. Making. IO/vite – react -…

The source address

Github.com/tcly861204/…

|-src
  |--main.jsx
  |--App.jsx
  |--libs
      |--utils.jsx
  |--bigdata
      |--body.jsx
      |--checkbox.jsx
      |--checkstyle.scss
      |--header.jsx
      |--index.jsx
      |--style.scss
Copy the code

The project just wrote out the solution, and ultimately had to deal with most of the details themselves

The source code interpretation

/* @author: tcly861204 @email: [email protected] @date: 2022/1/7 12:00:45@last Modified by: Tcly861204 @Last Modified Time: 2022/1/7 12:00:45 @Github: https://tcly861204.github.io */ import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react' import Header from './header' import Body from './body' import PropTypes from 'prop-types' import './style.scss' const BigData = (props) => { const { data, handleSelected } = props const bodyNode = useRef(null) const [columns, setColumns] = useState(props.columns || []) const [scrollWidth, setScrollWidth] = useState(8) const [scrollTop, setScrollTop] = useState(0) const [scrollLeft, setScrollLeft] = useState(0) const [leftColumns, setLeftColumns] = useState([]) const [rightColumns, setRightColumns] = useState([]) const [contentColumns, setContentColumns] = useState([]) const [rowHeight] = useState(props.rowHeight || 36) const [maxRow] = useState(props.maxRow || 15) const [isScroll, setIsScroll] = useState(false) useEffect(() => { setLeftColumns(columns.filter((item) => item.fixed === 'left')) setRightColumns(columns.filter((item) => item.fixed === 'right')) setContentColumns( columns.filter((item) => ! ['left', 'right'].includes(item.fixed)) ) }, [columns]) useEffect(() => { const timer = setTimeout(() => { const width = bodyNode.current.clientWidth const pwidth = bodyNode.current.parentNode.clientWidth setScrollWidth(pwidth - width) return () => { clearTimeout(timer) } }, 30) }, [data, bodyNode]) useEffect(() => { setIsScroll(data.length > maxRow) }, [data, maxRow]) const handleResizeColumn = useCallback( function (field, width) { if (! field) { return } const index = columns.findIndex((item) => item.prop === field) if (index >= 0) { const newColumns = [...columns] newColumns[index].width = width < 20 ? 20: width setColumns(newColumns) } }, [columns] ) const containerName = 'cui-bigdata-container' const leftWidth = useMemo( () => leftColumns.reduce((acc, item) => { return acc + (item.width || 100) }, 0), [leftColumns] ) const rightWidth = useMemo( () => rightColumns.reduce((acc, item) => { return acc + (item.width || 100) }, 0), [rightColumns] ) const controllerHeight = ((data.length > maxRow ? maxRow : data.length) + 1) * rowHeight const handleScroll = function (e) { const top = e.currentTarget.scrollTop const left = e.currentTarget.scrollLeft if (top ! == scrollTop) {setScrollTop(math.floor (top/rowHeight))} if (left! == scrollLeft) { setScrollLeft(left) } } const scrollHeight = data.length * rowHeight return ( <section className={containerName} style={{ height: `${controllerHeight + 2}px` }} > <section className={`${containerName}-header`}> <div className={`${containerName}_left`} style={{ width: `${leftWidth}px` }} > <Header columns={leftColumns} callback={handleResizeColumn} handleSelected={handleSelected} /> </div> <div className={`${containerName}_content`} style={{ left: `${leftWidth - scrollLeft}px`, right: `${ rightWidth + (isScroll ? scrollWidth : 0) - scrollLeft }px`, }} > <Header handleSelected={handleSelected} columns={contentColumns} callback={handleResizeColumn} /> </div> <div className={`${containerName}_right`} style={{ width: `${rightWidth + (isScroll ? scrollWidth : 0)}px`, right: 0, }} > <Header columns={rightColumns} callback={handleResizeColumn} /> </div> </section> <section className={`${containerName}-body`} style={{ height: `${controllerHeight - 36}px` }} onScroll={handleScroll} ref={bodyNode} > <div className={`${containerName}_left`} style={{ width: `${leftWidth}px`, left: `${scrollLeft}px`, height: `${scrollHeight}px`, }} > <Body {... props} maxRow={maxRow} scrollTop={scrollTop} columns={leftColumns} /> </div> <div className={`${containerName}_content`}  style={{ left: `${leftWidth}px`, right: `${rightWidth - scrollLeft}px`, height: `${scrollHeight}px`, }} > <Body {... props} maxRow={maxRow} scrollTop={scrollTop} columns={contentColumns} /> </div> <div className={`${containerName}_right`} style={{ width: `${rightWidth}px`, right: `${0 - scrollLeft}px`, height: `${scrollHeight}px`, }} > <Body {... props} maxRow={maxRow} scrollTop={scrollTop} columns={rightColumns} /> </div> <div className={`${containerName}_scroll`}  style={{ height: `${scrollHeight}px` }} /> </section> </section> ) } BigData.propTypes = { data: PropTypes.array, handleSelected: PropTypes.func, columns: PropTypes.array, rowHeight: PropTypes.number, maxRow: PropTypes.number, } export default BigDataCopy the code

Most of the processing is to display the page above, layout, and so on, the core of things is a scroll bar rolling distance monitoring body area How to get the position of the scroll, and then can get to the scroll bar top/rowHeight how much is just a line scrolling form distance, take this can go to calculate form needs to display the data, I have a default table showing 15 pieces of data

/* @author: tcly861204 @email: [email protected] @date: 2022/1/7 12:00:45@last Modified by: Tcly861204 @Last Modified Time: 2022/1/7 12:00:45 @Github: https://tcly861204.github.io */ import React from 'react' import PropTypes from 'prop-types' import Checkbox from './checkbox' function Body(props) { const { data, scrollTop, maxRow, columns, deleteCallback } = props const len = data.length > 15 ? 15 : data.length const renderCell = function (item, index) { if (item.component && item.type ! == 'delete') { return <item.component index={index} /> } else if (item.prop) { return <div className="cell line-clamp">{data[index][item.prop]}</div> } else { switch (item.type) { case 'index': return <div className="cell">{index + 1}</div> case 'selection': return ( <div className="cell"> <Checkbox value={data[index]._checked || false} /> </div> ) case 'delete': if (item.component) { return <item.component index={index} callback={deleteCallback} /> } return null default: return null } } } const renderColumns = function () { const rows = [] let maxLen = 0 const className = 'cui-bigdata-container' const dataLen = data.length if (dataLen > maxRow) { if (scrollTop < dataLen - maxRow - 4) { maxLen = scrollTop + maxRow + 3 } else { maxLen = dataLen } } else { maxLen = data.length } for (let row = scrollTop; row < maxLen; row++) { rows.push( <div key={row} className={`${className}-row`} style={{ transform: `translateY(${row * 36}px)` }} > {columns.map((item, col) => { return ( <li key={col} className={`align-${item.align || 'left'}`} style={ item.width ? { width: `${item.width}px`, maxWidth: `${item.width}px`, minWidth: `${item.width}px`, } : { display: 1, } } > {renderCell(item, row)} </li> ) })} </div> ) } return rows } return ( <div className="table-body" style={{ height: `${len * 36}px` }}> {renderColumns()} </div> ) } Body.propTypes = { data: PropTypes.array.isRequired, scrollTop: PropTypes.number.isRequired, maxRow: PropTypes.number.isRequired, columns: PropTypes.array, deleteCallback: PropTypes.func, } export default BodyCopy the code

So here we have the scrollTop for each scroll, which is basically the starting index of the data in the available area, startIndex, and then we add 15, which is the default display, which is the final render

conclusion

All big data is optimized by minimizing DOM rendering as much as possible. In the end, REACT seems to perform better in rendering such large data than VUE. I wrote it in VUE first and implemented a version of React in the same way later