React性能优化之SCU

news/2024/7/15 18:08:10 标签: react.js, javascript, 前端

一、概念

shouldComponentUpdate简称SCU,是React中性能优化的重要一环。

javascript">shouldComponentUpdate(nextProps, nextState) {
    // 判断是否需要被渲染,如果需要则返回true,否则返回false 
    if (nextProps.b === this.props.b) {
        return false;
    } else {
        return true;
    }
}

二、使用场景

react同一父组件的所有子组件中有一个更新,剩下的所有子组件都会重新渲染,但是为了性能,我们不需要让未更新依赖的组件更新。SCU就是解决这个未更新依赖的组件的重新渲染问题。

三、SCU实战(浅比较已适用大部分情况,尽量不要深度比较)

1、基本使用方法

例1:

javascript">import React from 'react'

class App extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          count: 0
      }
  }
  render() {
      return <div>
          <span>{this.state.count}</span>
          <button onClick={this.onIncrease}>increase</button>
      </div>
  }
  onIncrease = () => {
      this.setState({
          count: this.state.count + 1
      })
  }
  // 演示 shouldComponentUpdate 的基本使用
  shouldComponentUpdate(nextProps, nextState) {
      if (nextState.count !== this.state.count) {
          return true // 可以渲染
      }
      return false // 不重复渲染
  }
}

export default App

例1:

javascript">import React from 'react'
import PropTypes from 'prop-types'

class Input extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            title: ''
        }
    }
    render() {
        return <div>
            <input value={this.state.title} onChange={this.onTitleChange}/>
            <button onClick={this.onSubmit}>提交</button>
        </div>
    }
    onTitleChange = (e) => {
        this.setState({
            title: e.target.value
        })
    }
    onSubmit = () => {
        const { submitTitle } = this.props
        submitTitle(this.state.title) // 'abc'

        this.setState({
            title: ''
        })
    }
}
// props 类型检查
Input.propTypes = {
    submitTitle: PropTypes.func.isRequired
}

class List extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        const { list } = this.props

        return <ul>{list.map((item, index) => {
            return <li key={item.id}>
                <span>{item.title}</span>
            </li>
        })}</ul>
    }
}
// props 类型检查
List.propTypes = {
    list: PropTypes.arrayOf(PropTypes.object).isRequired
}

class Footer extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return <p>
            {this.props.text}
            {this.props.length}
        </p>
    }
    componentDidUpdate() {
        console.log('footer did update')
    }
    shouldComponentUpdate(nextProps, nextState) {
      console.log(nextProps, this.props)
        if (nextProps.text !== this.props.text) { //  || nextProps.length !== this.props.length
          return true // 可以渲染
        }
        return false // 不重复渲染
    }

    // React 默认:父组件有更新,子组件则无条件也更新!!!
    // 性能优化对于 React 更加重要!
    // SCU 一定要每次都用吗?—— 需要的时候才优化
}

class TodoListDemo extends React.Component {
    constructor(props) {
        super(props)
        // 状态(数据)提升
        this.state = {
            list: [
                {
                    id: 'id-1',
                    title: '标题1'
                },
                {
                    id: 'id-2',
                    title: '标题2'
                },
                {
                    id: 'id-3',
                    title: '标题3'
                }
            ],
            footerInfo: '底部文字'
        }
    }
    render() {
        return <div>
            <Input submitTitle={this.onSubmitTitle}/>
            <List list={this.state.list}/>
            <Footer text={this.state.footerInfo} length={this.state.list.length}/>
        </div>
    }
    onSubmitTitle = (title) => {
        this.setState({
            list: this.state.list.concat({
                id: `id-${Date.now()}`,
                title
            })
        })
    }
}

export default TodoListDemo 

例3:

javascript">import React from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash'

class Input extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            title: ''
        }
    }
    render() {
        return <div>
            <input value={this.state.title} onChange={this.onTitleChange}/>
            <button onClick={this.onSubmit}>提交</button>
        </div>
    }
    onTitleChange = (e) => {
        this.setState({
            title: e.target.value
        })
    }
    onSubmit = () => {
        const { submitTitle } = this.props
        submitTitle(this.state.title)

        this.setState({
            title: ''
        })
    }
}
// props 类型检查
Input.propTypes = {
    submitTitle: PropTypes.func.isRequired
}

class List extends React.Component {
  constructor(props) {
      super(props)
  }
  render() {
    const { list } = this.props

    return <ul>{list.map((item, index) => {
        return <li key={item.id}>
            <span>{item.title}</span>
        </li>
    })}</ul>
  }
  componentDidUpdate() {
    console.log('List did update')
  }

  // 增加 shouldComponentUpdate
  shouldComponentUpdate(nextProps, nextState) {
    console.log(nextProps.list, this.props.list)
      // _.isEqual 做对象或者数组的深度比较(一次性递归到底)
      if (_.isEqual(nextProps.list, this.props.list)) {
          // 相等,则不重复渲染
          return false
      }
      return true // 不相等,则渲染
  }
}
// props 类型检查
List.propTypes = {
    list: PropTypes.arrayOf(PropTypes.object).isRequired
}

class TodoListDemo extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          list: [
              {
                  id: 'id-1',
                  title: '标题1'
              },
              {
                  id: 'id-2',
                  title: '标题2'
              },
              {
                  id: 'id-3',
                  title: '标题3'
              }
          ]
      }
  }
  render() {
      return <div>
          <Input submitTitle={this.onSubmitTitle}/>
          <List list={this.state.list}/>
      </div>
  }
  onSubmitTitle = (title) => {
      // 正确的用法
      this.setState({
          list: this.state.list.concat({
              id: `id-${Date.now()}`,
              title
          })
      })

      // // 为了演示 SCU ,故意写的错误用法   SCU要配合不可变值
      // this.state.list.push({      // 已经改了 再setState都一样了 nextProps === this.props了  SCU返回false就不更新了
      //     id: `id-${Date.now()}`,
      //     title
      // })
      // this.setState({
      //     list: this.state.list
      // })
  }
}

export default TodoListDemo

在这里插入图片描述

2、PureComponent方法(类组件)

类组件 extends pureComponent的时候 当前组件也是浅比较的scu
在这里插入图片描述

例1:

javascript">import React from 'react'
import PropTypes from 'prop-types'

class Input extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          title: ''
      }
  }
  render() {
    return <div>
      <input value={this.state.title} onChange={this.onTitleChange}/>
      <button onClick={this.onSubmit}>提交</button>
    </div>
  }
  onTitleChange = (e) => {
    this.setState({
        title: e.target.value
    })
  }
  onSubmit = () => {
    const { submitTitle } = this.props
    submitTitle(this.state.title)

    this.setState({
        title: ''
    })
  }
}
// props 类型检查
Input.propTypes = {
  submitTitle: PropTypes.func.isRequired
}

class List extends React.PureComponent {
  constructor(props) {
      super(props)
  }
  componentDidUpdate() {
    console.log('List did update')
  }
  render() {
    const { list } = this.props

    return <ul>{list.map((item, index) => {
        return <li key={item.id}>
            <span>{item.title}</span>
        </li>
    })}</ul>
  }
  // shouldComponentUpdate() {/*浅比较*/}  其实就相当于加了这个 做浅比较
}
// props 类型检查
List.propTypes = {
  list: PropTypes.arrayOf(PropTypes.object).isRequired
}

class TodoListDemo extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [
          {
              id: 'id-1',
              title: '标题1'
          },
          {
              id: 'id-2',
              title: '标题2'
          },
          {
              id: 'id-3',
              title: '标题3'
          }
      ]
    }
  }
  render() {
    return <div>
        <Input submitTitle={this.onSubmitTitle}/>
        <List list={this.state.list}/>
    </div>
  }
  onSubmitTitle = (title) => {
    // 正确的用法
    this.setState({
        list: this.state.list.concat({
            id: `id-${Date.now()}`,
            title
        })
    })

    // // 为了演示 SCU ,故意写的错误用法
    // this.state.list.push({
    //     id: `id-${Date.now()}`,
    //     title
    // })
    // this.setState({
    //     list: this.state.list
    // })
  }
}

export default TodoListDemo

3、React.memo高阶组件(函数组件)

React.memo 这个高阶函数 可以叫高阶组件
React.memo 这个高阶组件做scu 也是浅比较的scu
在这里插入图片描述

四、性能优化小结

immutable.js
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


http://www.niftyadmin.cn/n/5096978.html

相关文章

el-pagination怎么修改样式,分页修改样式

/* 分页距离右边20&#xff0c;距离底边20 */ .pagination-container .el-pagination{position:absolute;right:20px;bottom:20px;} 自己写一个分页组件&#xff0c;用到绝对定位和相对定位

动态规划-买卖股票系列

121.买卖股票的最佳时机 Python: class Solution(object):def maxProfit(self, prices):""":type prices: List[int]:rtype: int"""if len(prices)0:return 0dplen(prices)*[0]minpriceint(prices[0])for i in range (1,len(prices)):minprice…

QGIS提取两条线元素的交点

**选择图层 Vector -> Analysis Tools**

极智AI | 先进封装技术Chiplet

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 先进封装技术Chiplet。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 芯片先进封装技术是个神秘且高科技的领域,…

BUUCTF-做题记录

很久没做题了&#xff0c;还是随便来水一水吧&#xff0c;之前都在学别的。 目录 [INSHack2017]remote-multimedia-controller[INSHack2017]hiding-in-plain-sight[QCTF2018]X-man-Keyword[BSidesSF2019]diskimage[2022红包题]虎年大吉[WMCTF2020]行为艺术[MRCTF2020]寻找xxx[…

电力配电机房监控方案

电力配电机房是电力系统的核心组成部分&#xff0c;对于电力运行和供电质量至关重要。为了确保电力系统的安全和稳定运行&#xff0c;监控机房的关键参数和状态变化变得至关重要。星创易联的4G工业路由器SR500和DTU200是一套先进的解决方案&#xff0c;能够实现对电力配电机房的…

半导体行业化学机械抛光为什么选用PFA量筒

量筒作为实验室中使用的一种量器&#xff0c;为竖长的圆筒形&#xff0c;上沿一侧有嘴&#xff0c;便于倾倒。下部有宽脚以保持稳定。圆筒壁上刻有容积量程。 常规用途 用来测液体体积的容器有很多&#xff0c;还有刻度吸管、移液管和滴管&#xff0c;前两者都比量筒的准确性…

postman如何使用md5 、base64加密传参

使用CryptoJS库 什么是CryptoJS&#xff1f; CryptoJS是一个纯JavaScript实现的加密库&#xff0c;提供了很多常见的加密算法和加密模式&#xff0c;例如AES、DES、TripleDES、MD5、SHA-1、SHA-256等。它支持的加密方式很全面&#xff0c;使用简便&#xff0c;而且在前端中使用…