react 组件进阶之 pureComponent(纯组件)

简介: react 组件进阶之 pureComponent(纯组件)

阅读下面的代码,请回答 render 总共执行了多少次?这个问题涉及到react的生命周期。

代码如下


import React, { Component, PureComponent } from 'react'
/**
 * 组件有两个状态,一个是li,另一个是添加li
 */
interface ITestPureComponentS {
  lis: number[],
  addLi: (li: number) => void
}
// 测试li 组件
class TestLi extends Component {
  render() {
    console.log('TestLi render');
    return (
      <li>{this.props.children}</li>
    )
  }
}
export default class TestPureComponent extends Component<{}, ITestPureComponentS> {
  state = {
    lis: [],
    addLi: (li: number) => {
      this.setState({
        lis: [...this.state.lis, li]
      })
    }
  }
  // 组件即将渲染的时候,添加10个li
  componentDidMount() {
    let lis: number[] = []
    for (let i = 1; i <= 10; i++) {
      lis.push(i)
    }
    this.setState({
      lis: lis
    })
  }
  /**
   * 添加一个li
   */
  addLis = () => {
    const num = Date.now()
    this.state.addLi(num)
  }
  render() {
    console.log('TestPureComponent render');
    const lisD = this.state.lis.map(i => {
      return (
        <TestLi key={i}>{i}</TestLi>
      )
    })
    return (
      <div>
        {lisD}
        <button onClick={this.addLis}>添加一个li</button>
      </div>
    )
  }
}


20210313095708397.png


分析


  • app 组件: 这里只是直接挂载,没有做任何操作,所以render 只会执行一次
  • TestPureComponent组件: 组件挂载阶段, 是需要执行一次的,然后组件挂载完毕后,我们手动setState({}) ,调用这个方法是会触发组件的render()函数的。 然后它还要在执行一次,所以这个组件的render() 总共执行两次
  • TestLi组件: 在父组件被render的同时子组件也会调用render(), 我们这里是直接使用 this.state.lis 的,一开始是空的,里面是没有 TestLi 组件的. 所以该组件执行的次数 应该为 10 次


打印结果


20210313100744393.png


如果可以答对的网友,恭喜你,对react 的生命周期还是蛮清楚的。加油,继续往下


点击,添加一个li render 又会执行多少次?


分析


  • TestPureComponent 组件: 点击按钮会触发 this.setState() 所以,TestPureComponent 组件必然会执行 render() ,该组件会执行 render 1次
  • TestLi组件 由于父组件执行render 并且数据发生变化,里面的值多了一个,所以改组件会执行 11 次


效果


20210313104054377.png


注意: 我们只是加了一个数据,并且数据都没有变化,为啥要渲染11次呀,这个render 虽然只是一点点的性能,如果组件树大了,那么render的次数也会相应的变得庞大。这个是非常影响性能的。所以有没有啥优化方法?


优化方法一: 代码结构优化,我们不在render()这里 进行map遍历,而是直接在componentDidMount的时候直接生成一个TestLi组件的数组,然后改变数据就不会重新渲染了, 如果网友你能想到这个问题?那确实你react 方面掌握的是非常厉害的。本人是刚刚误打误撞发现的。但是在大部分同学写代码都不怎么能优化,所以选择优化方法二;


优化方法二:shouldComponentUpdate(nextProps, nextState) 这里面能够直接决定是否需要重新 执行 render, 所以优化的方法就在这个路口,优化的思路也是比较容易的,将传递过来的state 和 props 和当前的 state, props进行比较,如果变化了,那么直接return true, 否则 return false;


在TestLi组件中进行优化


// 测试li 组件
class TestLi extends Component {
  /**
   * 浅判断
   * @param obj 
   * @param obj2 
   * @returns 
   */
  objectIsEqual(obj: any, obj2: any) {
    for (const key in obj) {
      if (Object.is(obj[key], obj2[key])) {
        return true;
      }
    }
    return false
  }
  shouldComponentUpdate(nextProps: {}, nextState: {}) {
    if (this.objectIsEqual(nextProps, this.props)) {
      return false;
    }
    return true
  }
  render() {
    console.log('TestLi render');
    return (
      <li>{this.props.children}</li>
    )
  }
}


效果


20210313110723649.png


注意: 有的网友又要问了,为啥要使用浅比较 而不进行深比较,个人决定浅比较不怎么消耗内存,省时省力。如果深度比较的话,那么就会比较消耗内存了,并且我们是在做优化操作,不需要进行深度比较。


PureComponent


PureComponent 就是上面TaskLi 里面封装的一个组件,改组件继承component, 里面的实现思路也是一样的,都是在shouldComponentUpdate 这里进行操作的,也是使用的是浅比较

代码改写成这样,也是可以实现一样的效果


// 测试li 组件
class TestLi extends PureComponent {
  render() {
    console.log('TestLi render');
    return (
      <li>{this.props.children}</li>
    )
  }
}

20210313111224511.png


注意


1.pureComponent 是纯组件,进行的是浅比较,因此数据如果涉及到引用类型的,如对象或者数组等,需要重新创建一个,不然是无法进行数据更新的。为了效率,我们应该使用这个组件


2.要求不改变之前的状态,需要对状态进行覆盖(Immutable)这个公共库可以避免我们犯错,具体的请自行查看。


3.如果函数组件需要使用纯组件,需要使用 React.memo 制作村组件,这个memo就是一个高阶组件,里面返回的还是一个类组件。有兴趣的自己编写

相关文章
|
24天前
|
前端开发 开发者
React 函数组件与类组件对比
【10月更文挑战第4天】本文详细比较了React中的函数组件与类组件。函数组件是一种简单的组件形式,以纯函数的形式返回JSX,易于理解与维护,适用于简单的UI逻辑。类组件则是基于ES6类实现的,需要重写`render`方法并能利用更多生命周期方法进行状态管理。文章通过示例代码展示了两者在状态管理与生命周期管理上的差异,并讨论了常见的问题如状态更新异步性与生命周期管理的复杂性,最后给出了相应的解决方法。通过学习,开发者可以根据具体需求选择合适的组件类型。
47 8
|
22天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
118 2
|
2月前
|
前端开发 JavaScript 网络架构
react对antd中Select组件二次封装
本文介绍了如何在React中对Ant Design(antd)的Select组件进行二次封装,包括创建MSelect组件、定义默认属性、渲染Select组件,并展示了如何使用Less进行样式定义和如何在项目中使用封装后的Select组件。
74 2
react对antd中Select组件二次封装
|
3天前
|
前端开发 JavaScript 安全
学习如何为 React 组件编写测试:
学习如何为 React 组件编写测试:
13 2
|
10天前
|
前端开发 JavaScript 测试技术
React 高阶组件 (HOC) 应用
【10月更文挑战第16天】高阶组件(HOC)是 React 中一种复用组件逻辑的方式,通过接受一个组件并返回新组件来实现。本文介绍了 HOC 的基础概念、核心功能和常见问题,包括静态方法丢失、ref 丢失、多个 HOC 组合和 props 冲突的解决方案,并提供了具体的 React 代码示例。通过本文,读者可以更好地理解和应用 HOC,提高代码的复用性和可维护性。
29 8
|
9天前
|
缓存 前端开发 JavaScript
前端serverless探索之组件单独部署时,利用rxjs实现业务状态与vue-react-angular等框架的响应式状态映射
本文深入探讨了如何将RxJS与Vue、React、Angular三大前端框架进行集成,通过抽象出辅助方法`useRx`和`pushPipe`,实现跨框架的状态管理。具体介绍了各框架的响应式机制,展示了如何将RxJS的Observable对象转化为框架的响应式数据,并通过示例代码演示了使用方法。此外,还讨论了全局状态源与WebComponent的部署优化,以及一些实践中的改进点。这些方法不仅简化了异步编程,还提升了代码的可读性和可维护性。
|
21天前
|
前端开发 JavaScript 调度
React 组件状态(State)
10月更文挑战第8天
13 1
|
2月前
|
前端开发
React给antd中TreeSelect组件左侧加自定义图标icon
本文介绍了如何在React中为Ant Design的TreeSelect组件的每个树节点添加自定义图标,并解决了因缺少key属性而导致的警告问题,展示了如何通过递归函数处理treeData数据并为每个节点添加图标。
61 2
React给antd中TreeSelect组件左侧加自定义图标icon
|
2月前
|
前端开发
React添加路径别名alias、接受props默认值、并二次封装antd中Modal组件与使用
本文介绍了在React项目中如何添加路径别名alias以简化模块引入路径,设置组件props的默认值,以及如何二次封装Ant Design的Modal组件。文章还提供了具体的代码示例,包括配置Webpack的alias、设置defaultProps以及封装Modal组件的步骤和方法。
60 1
React添加路径别名alias、接受props默认值、并二次封装antd中Modal组件与使用
|
28天前
|
JavaScript 前端开发 安全
使用 TypeScript 加强 React 组件的类型安全
【10月更文挑战第1天】使用 TypeScript 加强 React 组件的类型安全
36 3