React中使用LazyBuilder实现页面懒加载方法二

前言:

        在一个表格中,需要展示100条数据,当每条数据里面需要承载的内容很多,需要渲染的元素也很多的时候,容易造成页面加载的速度很慢,不能给用户提供很好的体验时,懒加载是优化页面加载速度的方法之一。

策略:
        前端在接受到api返回的数据的时候,可以先根据数据总的条数进行遍历,给每一项初始化简单的dom进行渲染占位,通过IntersectionObserver对每一项元素进行监听,当初始dom出现在页面视口的时候,需要替换掉初始dom,渲染真实dom。这样可以实现:在初始dom出现在视口内时,替换掉初始dom,渲染真实dom,并取消对该dom的监听,实现只需加载一次,首次加载多少个真实dom,取决于可视区域跟初始dom的高度

React中使用LazyBuilder实现页面懒加载方法一

与方法一不同之处:

方法一:元素出现在可视区域内,即渲染真实dom,一旦消失在可视区域内,即渲染初始dom

方法二:元素只要出现在可视区域内一次,即渲染真实dom,并且取消对该dom的监听,只需加载一次

LazyBuilder.jsx
import React, { Component, createRef } from "react";
class LazyBuilder extends Component {
  static defaultProps = {
      initComponent: null,
      initHeight: null,
      controller: null,
      className: null,
      style: null,
  }
  /**
   * @param {Object} props
   * @param {JSX.Element} [props.initComponent] - 默认组件
   * @param {Number} [props.initHeight] - 组件高度
   * @param {LazyController} [props.controller] - LazyController
   */
  constructor(props) {
    super(props);
    this._ref = createRef();
    this.controller = this.props.controller instanceof LazyController ? this.props.controller : new LazyController();
    this.state = {
        isLoading: true,
        initStyle: {
          width: "100%",
          height: props.initHeight
        },
        key: `lazy_${Math.random().toString(16).slice(2)}`,
    }
  }

  componentDidMount() {
    // 页面初始化时,对所有元素进行绑定监听
    this.controller.observe(this._ref.current, this.updateShowElement.bind(this));
  }

  // 组件销毁时
  componentWillUnmount() {
    const { autoDispose } = this.props;
    if (autoDispose && this.controller.size() === 0) {
      this.controller.dispose();
      return;
    }
    this.controller.unobserve(this._ref.current);
  }

  updateShowElement = () => {
    // 元素出现在视口以内
    this.setState({
      isLoading: false,
      initStyle: null,
    });
  }

  render () {
    const { children, initComponent } = this.props;
    const { isLoading, initStyle } = this.state;
    const className = ["lazy-builder-item", this.props.className].filter(item => typeof item === "string").join("\s");
    return (
        
{ isLoading ? initComponent : children }
); } } class LazyController { constructor(){ // 定义map来存储所有的dom项 this._map = new Map(); // IntersectionObserver 对每一项元素进行监听 this.observer = new IntersectionObserver((entries) => { for (const entry of entries) { // isIntersecting: true - 出现在视口 false - 隐藏(视口以外) if (entry.isIntersecting) { const updateShowElement = this._map.get(entry.target); if (typeof updateShowElement === "function") { updateShowElement() } this.unobserve(entry.target); } } }); } // 观察指定DOM observe = (target, callback) => { if (this.observer && !this.has(target)) { this._map.set(target, callback); this.observer.observe(target); } } // 取消对指定DOM的观察 unobserve = (target) => { if (this.observer && this.has(target)) { this.observer.unobserve(target); this._map.delete(target); } } // 判断一个DOM是否正在被观察 has = (target) => { return this._map.has(target); } // 返回正在观测中的DOM数量 size = () => { return this._map.size(); } // 停止对所有DOM的观测并销毁IntersectionObserver实例 dispose = () => { if (this.observer == null) { throw new Error("observer未初始化"); } this._map.clear(); this.observer.disconnect(); this.observer = null; } } export { LazyBuilder, LazyController, }

Cp.jsx

export default class  Cp extends Component {
  constructor(props){
    super(props)

    // 创建controller
    this.controller = new LazyController();
    this.state = {
      // 模拟数据
      dataList: new Array(100).fill().map((item, index) => index + 1)
    }
  }

  componentWillUnmount() {
    this.controller.dispose();
  }

  render(){
    const {dataList} = this.state
    return (
      
{ Array.isArray(dataList) && dataList.length > 0 ? dataList.map((item, index) => { return
{`第${item}个元素`}
}) : null }
) } }

初次加载:

React中使用LazyBuilder实现页面懒加载方法二_第1张图片

滚动后:

React中使用LazyBuilder实现页面懒加载方法二_第2张图片

你可能感兴趣的:(React.js,react.js,LazyBuilder,前端)