IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> react性能优化有哪些 -> 正文阅读

[JavaScript知识库]react性能优化有哪些

一、shouldComponentUpdate

shouldComponentUpdate(nextProps, nextState) {
  return true;
}
  • nextProps: 表示下一个props
  • nextState: 表示下一个state的值。

默认返回true,让react执行更新

举例:

  constructor(props) {
    super(props);
    this.state = {count: 1};
  }
 
  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {   //判断color是否改变
      return true;
    }
    if (this.state.count !== nextState.count) {   //判断count是否改变
      return true;
    }
    return false;    //如果两个都不改变,则不重新渲染
  }

只有当 props.color 或者 state.count 的值改变才需要更新时,你可以使用 shouldComponentUpdate 来进行检查

使用 Immutable

我们了解到使用?Immutable可以给?React?应用带来性能的优化,主要体现在减少渲染的次数

在做react性能优化的时候,为了避免重复渲染,我们会在shouldComponentUpdate()中做对比,当返回true执行render方法

Immutable通过is方法则可以完成对比,而无需像一样通过深度比较的方式比较

二、PureComponent

在上面例子中,shouldComponentUpdate?仅检查了?props.color?或?state.count?是否改变。如果这些值没有改变,那么这个组件就不会更新。如果组件更复杂一下,你可以使用类“浅比较”的模式来检查props和state的所有的字段,以此来决定是否组件需要更新。react已经提供了一个好的帮手来帮实现这种模式:只要继承?React.PureComponent?就行了

例子:

class CounterButton extends React.PureComponent {    //继承PureComponent默认进行浅比较,决定                       
                                                     //是否重新渲染
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }
 
  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

大部分情况下,你可以使用 React.PureComponent 来代替手写 shouldComponentUpdate。但它只进行浅比较,所以当 props 或者 state 某种程度是可变的话(如数组元素、对象属性),浅比较会有遗漏,那你就不能使用它了。当数据结构很复杂时,情况会变得麻烦,这时还是需要自己手动写shouldComponentUpdate(不采用继承?PureComponent?的方式),在内部自己实现比较逻辑,决定是否重新渲染。

例如:

//此时color和count为obj的两个属性,如果采用继承PureComponent的方式,进行浅比较,但一直为同个对象
//这时即使内部属性改变,也检测不出来,导致一直不重新渲染
 
shouldComponentUpdate(nextProps, nextState) {
  if (this.props.obj.color !== nextProps.color) {   //判断obj.color是否改变
    return true;
  }
  if (this.state.obj.count !== nextState.count) {   //判断obj.count是否改变
    return true;
  }
  return false;    //如果两个属性都不改变,则不重新渲染
}

三、避免使用内联函数

如果我们使用内联函数,则每次调用render函数时都会创建一个新的函数实例,如下:

import React from "react";

export default class InlineFunctionComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Welcome Guest</h1>
        <input type="button" onClick={(e) => { this.setState({inputValue: e.target.value}) }} value="Click For Inline Function" />
      </div>
    )
  }
}

我们应该在组件内部创建一个函数,并将事件绑定到该函数本身。这样每次调用?render?时就不会创建单独的函数实例,如下:

import React from "react";

export default class InlineFunctionComponent extends React.Component {
  
  setNewStateData = (event) => {
    this.setState({
      inputValue: e.target.value
    })
  }
  
  render() {
    return (
      <div>
        <h1>Welcome Guest</h1>
        <input type="button" onClick={this.setNewStateData} value="Click For Inline Function" />
      </div>
    )
  }
}

四、使用 React Fragments 避免额外标记

用户创建新组件时,每个组件应具有单个父标签。父级不能有两个标签,所以顶部要有一个公共标签,所以我们经常在组件顶部添加额外标签div

这个额外标签除了充当父标签之外,并没有其他作用,这时候则可以使用fragement

其不会向组件引入任何额外标记,但它可以作为父级标签的作用,如下所示:

export default class NestedRoutingComponent extends React.Component {
    render() {
        return (
            <>
                <h1>This is the Header Component</h1>
                <h2>Welcome To Demo Page</h2>
            </>
        )
    }
}

五、事件绑定方式

从性能方面考虑,在render方法中使用bindrender方法中使用箭头函数这两种形式在每次组件render的时候都会生成新的方法实例,性能欠缺

constructorbind事件与定义阶段使用箭头函数绑定这两种形式只会生成一个方法实例,性能方面会有所改善

常见的绑定方式有如下:

  • render方法中使用bind

  • render方法中使用箭头函数

  • constructor中bind

  • 定义阶段使用箭头函数绑定

1、render方法中使用bind

如果使用一个类组件,在其中给某个组件/元素一个onClick属性,它现在并会自定绑定其this到当前组件,解决这个问题的方法是在事件函数后使用.bind(this)this绑定到当前组件中

class?App?extends?React.Component?{
??handleClick()?{
????console.log('this?>?',?this);
??}
??render()?{
????return?(
??????<div?onClick={this.handleClick.bind(this)}>test</div>
????)
??}
}

这种方式在组件每次render渲染的时候,都会重新进行bind的操作,影响性能

2、render方法中使用箭头函数

通过ES6的上下文来将this的指向绑定给当前组件,同样在每一次render的时候都会生成新的方法,影响性能

class?App?extends?React.Component?{
??handleClick()?{
????console.log('this?>?',?this);
??}
??render()?{
????return?(
??????<div?onClick={e?=>?this.handleClick(e)}>test</div>
????)
??}
}

3、constructor中bind

constructor中预先bind当前组件,可以避免在render操作中重复绑定

class?App?extends?React.Component?{
??constructor(props)?{
????super(props);
????this.handleClick?=?this.handleClick.bind(this);
??}
??handleClick()?{
????console.log('this?>?',?this);
??}
??render()?{
????return?(
??????<div?onClick={this.handleClick}>test</div>
????)
??}
}

4、定义阶段使用箭头函数绑定

跟上述方式三一样,能够避免在render操作中重复绑定,实现也非常的简单,如下:

class?App?extends?React.Component?{
??constructor(props)?{
????super(props);
??}
??handleClick?=?()?=>?{
????console.log('this?>?',?this);
??}
??render()?{
????return?(
??????<div?onClick={this.handleClick}>test</div>
????)
??}
}
  • 编写方面:方式一、方式二写法简单,方式三的编写过于冗杂

  • 性能方面:方式一和方式二在每次组件render的时候都会生成新的方法实例,性能问题欠缺。若该函数作为属性值传给子组件的时候,都会导致额外的渲染。而方式三、方式四只会生成一个方法实例

综合上述,方式四是最优的事件绑定方式

五、懒加载组件

从工程方面考虑,webpack存在代码拆分能力,可以为应用创建多个包,并在运行时动态加载,减少初始包的大小

而在react中使用到了Suspense和?lazy组件实现代码拆分功能,基本使用如下:

const?johanComponent?=?React.lazy(()?=>?import(/*?webpackChunkName:?"johanComponent"?*/?'./myAwesome.component'));
?
export?const?johanAsyncComponent?=?props?=>?(
??<React.Suspense?fallback={<Spinner?/>}>
????<johanComponent?{...props}?/>
??</React.Suspense>
);

六、useMemo性能优化

import React, { useState, memo, useMemo } from 'react'

// 子组件
// function Child({ userInfo }) {
//     console.log('Child render...', userInfo)

//     return <div>
//         <p>This is Child {userInfo.name} {userInfo.age}</p>
//     </div>
// }
// 类似 class PureComponent ,对 props 进行浅层比较
const Child = memo(({ userInfo }) => {
    console.log('Child render...', userInfo)

    return <div>
        <p>This is Child {userInfo.name} {userInfo.age}</p>
    </div>
})

// 父组件
function App() {
    console.log('Parent render...')

    const [count, setCount] = useState(0)
    const [name, setName] = useState('小宗')

    // const userInfo = { name, age: 20 }
    // 用 useMemo 缓存数据,有依赖
    const userInfo = useMemo(() => {
        return { name, age: 21 }
    }, [name])

    return <div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo}></Child>
    </div>
}

export default App

总结:

  1. React默认会更新所以子组件
  2. class组件使用SCU和PureComponent做优化
  3. Hooks中使用useMemo,但优化原理是相同的

七、useCallback做性能优化

import React, { useState, memo, useMemo, useCallback } from 'react'

// 子组件,memo 相当于 PureComponent
const Child = memo(({ userInfo, onChange }) => {
    console.log('Child render...', userInfo)

    return <div>
        <p>This is Child {userInfo.name} {userInfo.age}</p>
        <input onChange={onChange}></input>
    </div>
})

// 父组件
function App() {
    console.log('Parent render...')

    const [count, setCount] = useState(0)
    const [name, setName] = useState('双越老师')

    // 用 useMemo 缓存数据
    const userInfo = useMemo(() => {
        return { name, age: 21 }
    }, [name])

    // function onChange(e) {
    //     console.log(e.target.value)
    // }
    // 用 useCallback 缓存函数
    const onChange = useCallback(e => {
        console.log(e.target.value)
    }, [])

    return <div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo} onChange={onChange}></Child>
    </div>
}

export default App

总结:

  1. useMemo 缓存数据
  2. useCallback 缓存函数
  3. 两者是Hooks的常见优化策略

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 07:59:01  更:2022-05-08 08:01:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:06:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码