1.长列表(城市列表,通讯录,微博等)大型数据表格会使页面出现卡顿,不流畅等性能问题
原因:大量的Dom重绘重排,或者设备老旧
解决:懒加载,可视区渲染
懒加载:(常用于移动端)
每次只渲染一部分数据,渲染的数据滚动时,在加载剩余部分
数据量不大时可以使用,不然会出现卡顿,不流畅等性能问题、
可视区渲染:(react- virtualized)
只渲染可视区列表的内容,看不见的区域不渲染,滚动列表区域时动态加载数据。
地址链接
安装:npm i react-virtualized
引入:import ‘react-virtualied/style.css’
地址链接
import React from 'react'
import { NavBar, Icon } from 'antd-mobile';
import './index.scss'
import axios from 'axios'
import {getCurrentCity} from '../../utils'
// 导入List组件
import {List, AutoSizer} from 'react-virtualized';
const TITLE_HIGHT = 36
const INDEX_CITY = 50
// 数据格式化方法
const formatDataCity = (list)=>{
const cityList = {}
// const cityIndex = []
// 1.遍历list数组
list.forEach(item=>{
// 2.获取每个城市首字母
const first= item.short.substr(0,1)
console.log(first)
// 3.判断cityList是否有该分类
if(cityList[first]){
// 4.如果有就往该分类中push数据
cityList[first].push(item)
} else{
// 5.如果没有就创建新数组存储
cityList[first] = [item]
}
})
// 获取索引数据
const cityIndex=Object.keys(cityList).sort()
return{
cityList,
cityIndex
}
}
// 封装处理索引方法
const formatCityIndex =(letter)=>{
switch (letter) {
case '#':
return '当前定位'
case 'hot':
return '热门城市'
default:
return letter.toUpperCase()
}
}
// 列表数据源
// const list = Array(100).fill('zujian')
export default class CityList extends React.Component{
constructor(props){
super(props)
this.state={
cityList:{},
cityIndex:[],
activeIndex:0
}
this.cityListComponent = React.createRef()
}
async componentDidMount(){
await this.getCityLists()
this.cityListComponent.current.measureAllRows()
}
// 获取城市列表数据
async getCityLists(){
const res = await axios.get('http://localhost:8080/area/city?level=1')
console.log(res)
const{cityList,cityIndex}= formatDataCity(res.data.body)
const hot = await axios.get('http://localhost:8080/area/hot')
cityList['hot'] = hot.data.body
// 将索引添加到cityIndex中
cityIndex.unshift('hot')
// 获取当前定位城市
const curCity = await getCurrentCity()
// 把当前定位城市加到cityList中
cityList['#'] = [curCity]
cityIndex.unshift('#')
console.log(cityList,cityIndex,curCity)
this.setState({
cityIndex,
cityList
})
}
// 渲染每一行数据的渲染函数 函数的返回值就是渲染在页面的每一行内容
rowRenderer=({
key, // Unique key within array of rows
index, // Index of row within collection
isScrolling, // The List is currently being scrolled
isVisible, // This row is visible within the List (eg it is not an overscanned row)
style, // Style object to be applied to row (to position it)
})=> {
const { cityIndex,cityList } = this.state
const letter = cityIndex[index]
return (
<div key={key} style={style} className="city">
<div className="title">{formatCityIndex(letter)}</div>
{
cityList[letter].map((item=><div className="name" key={item.value}>{item.label}</div>))
}
</div>
)
}
// 动态计算高度
getRowHight = ({index})=>{
const {cityList,cityIndex} = this.state
return TITLE_HIGHT+cityList[cityIndex[index]].length*INDEX_CITY
}
// 封装渲染右侧索引列表的方法
renderCityIndex() {
// 获取到 cityIndex,并遍历其,实现渲染
const { cityIndex, activeIndex } = this.state
return cityIndex.map((item, index) => (
<li className="city-index-item" key={item} onClick={()=>{
this.cityListComponent.current.scrollToRow(index)
}}>
<span className={activeIndex === index ? 'index-active' : ''}>
{item === 'hot' ? '热' : item.toUpperCase()}
</span>
</li>
))
}
// 用于获取list组件中渲染行的信息
onRowsRendered=({startIndex})=>{
if(this.state.activeIndex !== startIndex){
this.setState({
activeIndex:startIndex
})
}
}
render(){
return (
<div className="cityList">
<NavBar
mode="light"
icon={<i className="iconfont icon-back"/>}
onLeftClick={() => this.props.history.go(-1)}
>城市列表
</NavBar>
{/* list组件 */}
<AutoSizer>
{({height, width}) => (
<List
ref={this.cityListComponent}
height={height}
rowCount={this.state.cityIndex.length}
rowHeight={this.getRowHight}
rowRenderer={this.rowRenderer}
width={width}
onRowsRendered = {this.onRowsRendered}
scrollToAlignment="start"
/>
)}
</AutoSizer>
<ul className="city-index">
{this.renderCityIndex()}
</ul>
</div>
)
}
}