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 (
        <div id={this.state.key} ref={this._ref} className={className} style={Object.assign({}, initStyle, this.props.style)}>
          {
            isLoading ? initComponent : children
          }
        </div>
    );
  }
}

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 (
      <div>
        {
          Array.isArray(dataList) && dataList.length > 0
          ? dataList.map((item, index) => {
            return <LazyBuilder 
                    key={index}
                    initHeight={200} // 初始dom高度
                    controller={this.controller} // controller
                  >
                    <div style={{width: '100%', height: '200px'}}>{`第${item}个元素`}</div>
                  </LazyBuilder>
          })
          : null
        }
      </div>
    )
  }
}

初次加载:

滚动后:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/350987.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络协议测试】畸形数据包——圣诞树攻击(DOS攻击)

简介 TCP所有标志位被设置为1的数据包被称为圣诞树数据包&#xff08;XMas Tree packet&#xff09;&#xff0c;之所以叫这个名是因为这些标志位就像圣诞树上灯一样全部被点亮。 标志位介绍 TCP报文格式&#xff1a; 控制标志&#xff08;Control Bits&#xff09;共6个bi…

【虚拟机数据恢复】异常断电导致虚拟机无法启动的数据恢复案例

虚拟机数据恢复环境&#xff1a; 某品牌R710服务器MD3200存储&#xff0c;上层是ESXI虚拟机和虚拟机文件&#xff0c;虚拟机中存放有SQL Server数据库。 虚拟机故障&#xff1a; 机房非正常断电导致虚拟机无法启动。服务器管理员检查后发现虚拟机配置文件丢失&#xff0c;所幸…

JPDA框架和JDWP协议

前言 在逆向开发中,一般都需要对目标App进行代码注入。主流的代码注入工具是Frida,这个工具能稳定高效实现java代码hook和native代码hook,不过缺点是需要使用Root设备,而且用js开发,入门门槛较高。最近发现一种非Root环境下对Debug App进行代码注入的方案,原理是利用Jav…

Unity MonoBehaviour 生成dll

dllllllllllllll&#x1f953; &#x1f959;vs创建类库项目&#x1f9c0;添加UnityEngine、UnityEditor引用&#x1f355;添加MonoBehaviour类&#x1f9aa;设置dll生成路径&#x1f37f;生成dll&#x1f354;使用dll中的Mono类 &#x1f959;vs创建类库项目 &#x1f9c0;添加…

qiankun子应用静态资源404问题有效解决(涉及 css文件引用图片、svg图片无法转换成 base64等问题)

在&#x1f449;&#x1f3fb; qiankun微前端部署&#x1f448;&#x1f3fb;这个部署方式的前提下&#xff0c;遇到的问题并解决问题的过程 最开始的问题现象 通过http请求本地的静态json文件404css中部分引入的图片无法显示 最开始的解决方式 在&#x1f449;&#x1f3…

YOLO系列(YOLO1-YOLO5)技术规格、应用场景、特点及性能对比分析

文章目录 前言一、YOLOv1-YOLOv5技术规格对比&#xff1a;二、主要应用场景和特点&#xff1a;三、性能对比分析&#xff1a;四、市场应用前景及对不同用户群体的潜在影响&#xff1a;总结 前言 YOLO&#xff08;You Only Look Once&#xff09;系列模型作为一种实时目标检测算…

OpenAI 降低价格并修复拒绝工作的“懒惰”GPT-4,另外ChatGPT 新增了两个小功能

OpenAI降低了GPT-3.5 Turbo模型的API访问价格&#xff0c;输入和输出价格分别降低了50%和25%。这对于使用API进行文本密集型应用程序的用户来说是一个好消息。 OpenAI官网&#xff1a;OpenAI AIGC专区&#xff1a;aigc 教程专区&#xff1a;AI绘画&#xff0c;AI视频&#x…

npm,cnpm install报:Error: certificate has expired at TLSSocket.onConnectSecure

问题描述 最近发现前端项目 CI/CD 时失败&#xff0c;报下面的错误。npm淘宝镜像源证书过期导致的。 [npminstall:get] retry GET https://registry.npm.taobao.org/vue-router after 400ms, retry left 1, error: ResponseError: certificate has expired, GET https://reg…

【Unity小技巧】一个脚本实现控制3D远程/近战敌人AI

最终效果 文章目录 最终效果烘培导航地图配置敌人导航数据简单配置敌人动画敌人AI脚本完结 想了解导航的其他内容可以看我这篇文章&#xff1a;【Unity游戏开发教程】零基础带你从小白到超神29——导航系统 烘培导航地图 选中地面&#xff0c;设置为静态导航 点击烘培&#xf…

《动手学深度学习(PyTorch版)》笔记4.4

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过。…

写静态页面——魅族声学_前端页面练习

1、效果: 1、html代码: <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>魅族声学</titl…

5G时代下的融合CDN新风口

近年来&#xff0c;随着网络技术的飞速发展&#xff0c;互联网流量视频化的趋势日益明显&#xff0c;视频应用使互联网的可扩展性、可演进性、服务质量和网络安全面临诸多挑战。为克服传统IP网络在服务视频应用当中的不足&#xff0c;内容分发网络CDN被提出&#xff0c;并迅速成…

java servlet运输公司管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web运输公司管理系统是一套完善的java web信息管理系统 serlvetdaobean mvc 模式开发 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主 要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5…

Go的单元测试

开发项目过程中&#xff0c;少不了单元测试&#xff1b;下面我们认识下单元测试&#xff1a; Go 语言测试框架可以让我们很容易地进行单元测试&#xff0c;但是需要遵循五点规则。 含有单元测试代码的 go 文件必须以 _test.go 结尾&#xff0c;Go 语言测试工具只认符合这个规…

2. MySQL 多实例

重点&#xff1a; MySQL 的 三种安装方式&#xff1a;包安装&#xff0c;二进制安装&#xff0c;源码编译安装。 MySQL 的 基本使用 MySQL 多实例 DDLcreate alter drop DML insert update delete DQL select 2.5&#xff09;通用 二进制格式安装 MySQL 2.5.1&#xff…

JavaScript学习-原型和原型链

原型和原型链 示例代码 //创建一个Person类 class Person {constructor(name) {this.name name;}drink() {console.log(喝水);} } //创建一个Teacher类&#xff0c;继承Person class Teacher extends Person {constructor(name, subject) {super(name);this.subject subjec…

微信小程序 仿微信聊天界面

1. 需求效果图 2. 方案 为实现这样的效果&#xff0c;首先要解决两个问题&#xff1a; 2.1.点击输入框弹出软键盘后&#xff0c;将已有的少许聊天内容弹出&#xff0c;导致看不到的问题 点击输入框弹出软键盘后&#xff0c;将已有的少许聊天内容弹出&#xff0c;导致看不到的问…

FFMPEG解析ts流

三篇相关联的文章&#xff1a; ffmpeg下HLS解析过程-CSDN博客TS文件格式详解及解封装过程-CSDN博客 FFMPEG解析ts流-CSDN博客 一、简介 关于TS格式解析&#xff0c;可以参考《TS文件格式详解及解封装过程-CSDN博客》&#xff0c;本文主要代码部分解读。建议大家熟读iso138…

【JaveWeb教程】(30)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(3)员工管理的实现

目录 SpringBootWeb案例033. 员工管理3.1 分页查询3.1.1 基础分页3.1.1.1 需求分析3.1.1.2 接口文档3.1.1.3 思路分析3.1.1.4 功能开发3.1.1.5 功能测试3.1.1.6 前后端联调 3.1.2 分页插件3.1.2.1 介绍3.1.2.2 代码实现3.1.2.3 测试 3.2 分页查询(带条件)3.2.1 需求3.2.2 思路分…

电流检测电路设计方案汇总

电流检测电路设计方案&#xff08;一&#xff09; 低端检流电路的检流电阻串联到地&#xff08;图1&#xff09;&#xff0c;而高端检流电路的检流电阻是串联到高电压端&#xff08;图2&#xff09;。两种方法各有特点&#xff1a;低端检流方式在地线回路中增加了额外的线绕电…
最新文章