React 性能优化方法总结

目录
  • 前言
  • 为什么页面会出现卡顿的现象?
  • React 到底是在哪里出现了卡顿?
  • React 有哪些场景会需要性能优化?
    • 一:父组件刷新,而不波及子组件。
      • 第一种:使用 PureComponent
      • 第三种:函数组件如何判断props的变化的更新呢? 使用 React.memo函数
  • 使用 React.useMemo来实现对子组件的缓冲
    • 一:组件自己控制自己是否刷新
    • 三:减少波及范围,无关刷新数据不存入state中
      • 场景一:无意义重复调用setState,合并相关的state
      • 场景二:和页面刷新没有相关的数据,不存入state中
      • 场景三:通过存入useRef的数据中,避免父子组件的重复刷新
    • 四:合并 state,减少重复 setState 的操作
    • 五:如何更快的完成diff的比较,加快进程
  • 还有哪些工具可以提升性能呢?

前言

要讲清楚性能优化的原理,就需要知道它的前世今生,需要回答如下的问题:

  • React 是如何进行页面渲染的?
  • 造成页面的卡顿的罪魁祸首是什么呢?
  • 我们为什么需要性能优化?
  • React 有哪些场景会需要性能优化?
  • React 本身的性能优化手段?
  • 还有哪些工具可以提升性能呢?

为什么页面会出现卡顿的现象?

为什么浏览器会出现页面卡顿的问题?是不是浏览器不够先进?这都 2202 年了,怎么还会有这种问题呢?

实际上问题的根源来源于浏览器的刷新机制。

我们人类眼睛的刷新率是 60Hz,浏览器依据人眼的刷新率 计算出了

1000 Ms / 60 = 16.6ms

也就是说,浏览器要在16.6Ms 进行一次刷新,人眼就不会感觉到卡顿,而如果超过这个时间进行刷新,就会感觉到卡顿。

而浏览器的主进程在仅仅需要页面的渲染,还需要做解析执行Js,他们运行在一个进程中。

如果js的在执行的长时间占用主进程的资源,就会导致没有资源进行页面的渲染刷新,进而导致页面的卡顿。

那么这个又和 React 的性能优化又有什么关系呢?

React 到底是在哪里出现了卡顿?

基于我们上的知识,js 长期霸占浏览器主线程造成无法刷新而造成卡顿。

那么 React 的卡顿也是基于这个原因。

React 在render的时候,会根据现有render产生的新的jsx的数据和现有fiberRoot 进行比对,找到不同的地方,然后生成新的workInProgress,进而在挂载阶段把新的workInProgress交给服务器渲染。

在这个过程中,React 为了让底层机制更高效快速,进行了大量的优化处理,如设立任务优先级、异步调度、diff算法、时间分片等。

整个链路就是了高效快速的完成从数据更新到页面渲染的整体流程。

为了不让递归遍历寻找所有更新节点太大而占用浏览器资源,React 升级了fiber架构,时间分片,让其可以增量更新。

为了找出所有的更新节点,设立了diff算法,高效的查找所有的节点。

为了更高效的更新,及时响应用户的操作,设计任务调度优先级。

而我们的性能优化就是为了不给 React 拖后腿,让其更快,更高效的遍历。

那么性能优化的奥义是什么呢??

就是控制刷新渲染的波及范围,我们只让改更新的更新,不该更新的不要更新,让我们的更新链路尽可能的短的走完,那么页面当然就会及时刷新不会卡顿了。

React 有哪些场景会需要性能优化?

  • 父组件刷新,而不波及子组件
  • 组件自己控制自己是否刷新
  • 减少波及范围,无关刷新数据不存入state中
  • 合并 state,减少重复 setState 的操作
  • 如何更快的完成diff的比较,加快进程

我们分别从这些场景说一下:

一:父组件刷新,而不波及子组件。

我们知道 React 在组件刷新判定的时候,如果触发刷新,那么它会深度遍历所有子组件,查找所有更新的节点,依据新的jsx数据和旧的 fiber ,生成新的workInProgress,进而进行页面渲染。

所以父组件刷新的话,子组件必然会跟着刷新,但是假如这次的刷新,和我们子组件没有关系呢?怎么减少这种波及呢?

如下面这样:

export default function Father1 (){
    let [name,setName] = React.useState('');

    return (
        <div>
            <button onClick={()=>setName("获取到的数据")}>点击获取数据</button>
            {name}
            <Children/>
        </div>
    )
}

function Children(){
    return (
        <div>
            这里是子组件
        </div>
    )
}

运行结果: 

可以看到我们的子组件被波及了,解决办法有很多,总体来说分为两种:

  • 子组件自己判断是否需要更新 ,典型的就是 PureComponent,shouldComponentUpdate,memo
  • 父组件对子组件做个缓冲判断

第一种:使用 PureComponent

使用 PureComponent 的原理就是它会对state 和props进行浅比较,如果发现并不相同就会更新。

export default function Father1 (){
    let [name,setName] = React.useState('');
    return (
        <div>
            <button onClick={()=>setName("父组件的数据")}>点击刷新父组件</button>
            {name}

            <Children1/>
        </div>
    )
}
class Children extends React.PureComponent{
    render() {
        return (
            <div>这里是子组件</div>
        )
    }
}

执行结果:

实际上PureComponent就是在内部更新的时候调用了会调用如下方法来判断 新旧state和props

function shallowEqual(objA: mixed, objB: mixed): boolean {
  if (is(objA, objB)) {
    return true;
  }
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  if (keysA.length !== keysB.length) {
    return false;
  }
  // Test for A's keys different from B.
  for (let i = 0; i < keysA.length; i++) {
    const currentKey = keysA[i];
    if (
      !hasOwnProperty.call(objB, currentKey) ||
      !is(objA[currentKey], objB[currentKey])
    ) {
      return false;
    }
  }
  return true;
}

它的判断步骤如下:

  • 第一步,首先会直接比较新老 props 或者新老 state 是否相等。如果相等那么不更新组件。
  • 第二步,判断新老 state 或者 props ,有不是对象或者为 null 的,那么直接返回 false ,更新组件。
  • 第三步,通过 Object.keys 将新老 props 或者新老 state 的属性名 key 变成数组,判断数组的长度是否相等,如果不相等,证明有属性增加或者减少,那么更新组件。
  • 第四步,遍历老 props 或者老 state ,判断对应的新 props 或新 state ,有没有与之对应并且相等的(这个相等是浅比较),如果有一个不对应或者不相等,那么直接返回 false ,更新组件。 到此为止,浅比较流程结束, PureComponent 就是这么做渲染节流优化的。

在使用PureComponent时需要注意的细节;

由于PureComponent 使用的是浅比较判断stateprops,所以如果我们在父子组件中,子组件使用PureComponent,在父组件刷新的过程中不小心把传给子组件的回调函数变了,就会造成子组件的误触发,这个时候PureComponent就失效了。

细节一:函数组件中,匿名函数,箭头函数和普通函数都会重新声明

下面这些情况都会造成函数的重新声明:

箭头函数

 <Children1 callback={(value)=>setValue(value)}/>

匿名函数

<Children1 callback={function (value){setValue(value)}}/>

普通函数

export default function Father1 (){
    let [name,setName] = React.useState('');
    let [value,setValue] = React.useState('')
    const setData=(value)=>{
        setValue(value)
    }
    return (
        <div>
            <button onClick={()=>setName("父组件的数据"+Math.random())}>点击刷新父组件</button>
            {name}
            <Children1 callback={setData}/>
        </div>
    )
}
class Children1 extends React.PureComponent{
    render() {
        return (
            <div>这里是子组件</div>
        )
    }
}

执行结果:

可以看到子组件的 PureComponent 完全失效了。这个时候就可以使用useMemo或者 useCallback 出马了,利用他们缓冲一份函数,保证不会出现重复声明就可以了。

export default function Father1 (){
    let [name,setName] = React.useState('');
    let [value,setValue] = React.useState('')
    const setData= React.useCallback((value)=>{
        setValue(value)
    },[])

    return (
        <div>
            <button onClick={()=>setName("父组件的数据"+Math.random())}>点击刷新父组件</button>
            {name}
            <Children1 callback={setData}/>
        </div>
    )
}

看结果:

可以看到我们的子组件这次并没有参与父组件的刷新,在React Profiler中也提示,Children1并没有渲染。

细节二:class组件中不使用箭头函数,匿名函数

原理和函数组件中的一样,class 组件中每一次刷新都会重复调用render函数,那么render函数中使用的匿名函数,箭头函数就会造成重复刷新的问题。

export default class Father extends React.PureComponent{
    constructor(props) {
        super(props);
        this.state = {
            name:"",
            count:"",
        }
    }
    render() {
        return (
            <div>
                <button onClick={()=>this.setState({name:"父组件的数据"+Math.random()})}>点击获取数据</button>
                {this.state.name}
                <Children1 callback={()=>this.setState({count:11})}/>
            </div>
        )
    }
}

执行结果:

而优化这个非常简单,只需要把函数换成普通函数就可以。

export default class Father extends React.PureComponent{
    constructor(props) {
        super(props);
        this.state = {
            name:"",
            count:"",
        }
    }
    setCount=(count)=>{
        this.setState({count})
    }
    render() {
        return (
            <div>
                <button onClick={()=>this.setState({name:"父组件的数据"+Math.random()})}>点击获取数据</button>
                {this.state.name}
                <Children1 callback={this.setCount(111)}/>
            </div>
        )
    }
}

执行结果:

细节三:在 class 组件的render函数中bind 函数

这个细节是我们在class组件中,没有在constructor中进行bind的操作,而是在render函数中,那么由于bind函数的特性,它的每一次调用都会返回一个新的函数,所以同样会造成PureComponent的失效

export default class Father extends React.PureComponent{
    //...
    setCount(count){
        this.setCount({count})
    }
    render() {
        return (
            <div>
                <button onClick={()=>this.setState({name:"父组件的数据"+Math.random()})}>点击获取数据</button>
                {this.state.name}
                <Children1 callback={this.setCount.bind(this,"11111")}/>
            </div>
        )
    }
}

看执行结果:

优化的方式也很简单,把bind操作放在constructor中就可以了。

constructor(props) {
    super(props);
    this.state = {
        name:"",
        count:"",
    }
    this.setCount= this.setCount.bind(this);
}

执行结果就不在此展示了。

第二种:shouldComponentUpdate

class 组件中 使用 shouldComponentUpdate 是主要的优化方式,它不仅仅可以判断来自父组件的nextprops,还可以根据nextState和最新的nextContext来决定是否更新。

class Children2 extends React. PureComponent{
    shouldComponentUpdate(nextProps, nextState, nextContext) {
        //判断只有偶数的时候,子组件才会更新
        if(nextProps !== this.props && nextProps.count  % 2 === 0){
            return true;
        }else{
            return false;
        }
    }
    render() {
        return (
            <div>
                只有父组件传入的值等于 2的时候才会更新
                {this.props.count}
            </div>
        )
    }
}

它的用法也是非常简单,就是如果需要更新就返回true,不需要更新就返回false.

第三种:函数组件如何判断props的变化的更新呢? 使用 React.memo函数

React.memo的规则是如果想要复用最后一次渲染结果,就返回true,不想复用就返回false。 所以它和shouldComponentUpdate的正好相反,false才会更新,true就返回缓冲。

const Children3 = React.memo(function ({count}){
    return (
        <div>
            只有父组件传入的值是偶数的时候才会更新
            {count}
        </div>
    )
},(prevProps, nextProps)=>{
    if(nextProps.count % 2 === 0){
        return false;
    }else{
        return true;
    }
})

如果我们不传入第二个函数,而是默认让 React.memo包裹一下,那么它只会对props浅比较一下,并不会有比较state之类的逻辑。

以上三种都是我们为了应对父组件更新触发子组件,子组件决定是否更新的实现。 下面我们讲一下父组件对子组件缓冲实现的情况:

使用 React.useMemo来实现对子组件的缓冲

看下面这段逻辑,我们的子组件只关心count数据,当我们刷新name数据的时候,并不会触发刷新 Children1子组件,实现了我们对组件的缓冲控制。

export default function Father1 (){
    let [count,setCount] = React.useState(0);
    let [name,setName] = React.useState(0);
    const render = React.useMemo(()=><Children1 count = {count}/>,[count])
    return (
        <div>
            <button onClick={()=>setCount(++count)}>点击刷新count</button>
            <br/>
            <button onClick={()=>setName(++name)}>点击刷新name</button>
            <br/>
            {"count"+count}
            <br/>
            {"name"+name}
            <br/>
            {render}
        </div>
    )
}
class Children1 extends React.PureComponent{
    render() {
        return (
            <div>
                子组件只关系count 数据
                {this.props.count}
            </div>
        )
    }
}

执行结果: 当我们点击刷新name数据时,可以看到没有子组件参与刷新

当我们点击刷新count 数据时,子组件参与了刷新

一:组件自己控制自己是否刷新

这里就需要用到上面提到的shouldComponentUpdate以及PureComponent,这里不再赘述。

三:减少波及范围,无关刷新数据不存入state中

这种场景就是我们有意识的控制,如果有一个数据我们在页面上并没有用到它,但是它又和我们的其他的逻辑有关系,那么我们就可以把它存储在其他的地方,而不是state中。

场景一:无意义重复调用setState,合并相关的state

export default class Father extends React.Component{
    state = {
        count:0,
        name:"",
    }
    getData=(count)=>{
        this.setState({count});
        //依据异步获取数据
        setTimeout(()=>{
            this.setState({
                name:"异步获取回来的数据"+count
            })
        },200)
    }
    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("渲染次数,",++count,"次")
    }
    render() {
        return (
            <div>
                <button onClick={()=>this.getData(++this.state.count)}>点击获取数据</button>
                {this.state.name}
            </div>
        )
    }
}

React Profiler的执行结果:

可以看到我们的父组件执行了两次。 其中的一次是无意义的先setState保存一次数据,然后又根据这个数据异步获取了数据以后又调用了一次setState,造成了第二次的数据刷新.

而解决办法就是把这个数据合并到异步数据获取完成以后,一起更新到state中。

getData=(count)=>{
        //依据异步获取数据
        setTimeout(()=>{
            this.setState({
                name:"异步获取回来的数据"+count,
                count
            })
        },200)
}

看执行结果:只渲染了一次。

场景二:和页面刷新没有相关的数据,不存入state中

实际上我们发现这个数据在页面上并没有展示,我们并不需要把他们都存放在state 中,所以我们可以把这个数据存储在state之外的地方。

export default class Father extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            name:"",
        }
        this.count = 0;
    }
    getData=(count)=>{
        this.count = count;
        //依据异步获取数据
        setTimeout(()=>{
            this.setState({
                name:"异步获取回来的数据"+count,
            })
        },200)
    }
    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("渲染次数,",++count,"次")
    }
    render() {
        return (
            <div>
                <button onClick={()=>this.getData(++this.count)}>点击获取数据</button>
                {this.state.name}
            </div>
        )
    }
}

这样的操作并不会影响我们对它的使用。 在class组件中我们可以把数据存储在this上面,而在Function中,则我们可以通过利用 useRef 这个 Hooks 来实现同样的效果。

export default function Father1 (){
    let [name,setName] = React.useState('');
    const countContainer = React.useRef(0);
    const getData=(count)=>{
        //依据异步获取数据
        setTimeout(()=>{
            setName("异步获取回来的数据"+count)
            countContainer.current = count++;
        },200)
    }
    return (
        <div>
            <button onClick={()=>getData(++countContainer.current)}>点击获取数据</button>
            {name}
        </div>
    )
}

场景三:通过存入useRef的数据中,避免父子组件的重复刷新

假设父组件中有需要用到子组件的数据,子组件需要把数据回到返回给父组件,而如果父组件把这份数据存入到了 state 中,那么父组件刷新,子组件也会跟着刷新。 这种的情况我们就可以把数据存入到 useRef 中,以避免无意义的刷新出现。或者把数据存入到class的 this 下。

四:合并 state,减少重复 setState 的操作

合并 state ,减少重复 setState 的操作,实际上 React已经帮我们做了,那就是批量更新,在React18 之前的版本中,批量更新只有在 React自己的生命周期或者点击事件中有提供,而异步更新则没有,例如setTimeoutsetInternal等。

所以如果我们想在React18 之前的版本中也想在异步代码添加对批量更新的支持,就可以使用React给我们提供的api

import ReactDOM from 'react-dom';
const { unstable_batchedUpdates } = ReactDOM;

使用方法如下:

componentDidMount() {
    setTimeout(()=>{
        unstable_batchedUpdates(()=>{
            this.setState({ number:this.state.number + 1 })
            console.log(this.state.number)
            this.setState({ number:this.state.number + 1})
            console.log(this.state.number)
            this.setState({ number:this.state.number + 1 })
            console.log(this.state.number)
        })
    })
}

五:如何更快的完成diff的比较,加快进程

diff算法就是为了帮助我们找到需要更新的异同点,那么有什么办法可以让我们的diff算法更快呢?

那就是合理的使用key

diff的调用是在reconcileChildren中的reconcileChildFibers,当没有可以复用current fiber节点时,就会走mountChildFibers,当有的时候就走reconcileChildFibers

reconcilerChildFibers的函数中则会针render函数返回的新的jsx数据进行判断,它是否是对象,就会判断它的newChild.$$typeof是否是REACT_ELEMENT_TYPE,如果是就按单节点处理。 如果不是继续判断是否是REACT_PORTAL_TYPE或者REACT_LAZY_TYPE

继续判断它是否为数组,或者可迭代对象。

而在单节点处理函数reconcileSingleElement中,会执行如下逻辑:

  • 通过 key,判断上次更新的时候的 Fiber 节点是否存在对应的 DOM 节点。 如果没有 则直接走创建流程,新生成一个 Fiber 节点,并返回
  • 如果有,那么就会继续判断,DOM 节点是否可以复用?
  • 如果有,就将上次更新的 Fiber 节点的副本作为本次新生的Fiber 节点并返回
  • 如果没有,那么就标记 DOM 需要被删除,新生成一个 Fiber 节点并返回。
function reconcileSingleElement(
    returnFiber: Fiber,
    currentFirstChild: Fiber | null,
    element: ReactElement
): Fiber {
    const key = element.key; //jsx 虚拟 DOM 返回的数据
    let child = currentFirstChild;//当前的fiber 

    // 首先判断是否存在对应DOM节点
    while (child !== null) {
        // 上一次更新存在DOM节点,接下来判断是否可复用

        // 首先比较key是否相同
        if (child.key === key) {

            // key相同,接下来比较type是否相同

            switch (child.tag) {
                // ...省略case

                default: {
                    if (child.elementType === element.type) {
                        // type相同则表示可以复用
                        // 返回复用的fiber
                        return existing;
                    }

                    // type不同则跳出switch
                    break;
                }
            }
            // 代码执行到这里代表:key相同但是type不同
            // 将该fiber及其兄弟fiber标记为删除
            deleteRemainingChildren(returnFiber, child);
            break;
        } else {
            // key不同,将该fiber标记为删除
            deleteChild(returnFiber, child);
        }
        child = child.sibling;
    }

    // 创建新Fiber,并返回 ...省略
}

从上面的代码就可以看出,React 是如何判断一个 Fiber 节点是否可以被复用的。

  • 第一步:判断element的 key 和 fiber 的key 是否相同
  • 如果不相同,就会创建新的 Fiber,并返回
  • 第二步:如果相同,就判断element.typefiber的 type 是否相同,type 就是他们的类型,比如p标签就是p,div 标签就是div.如果 type 不相同,那么就会标识删除。
  • 如果相同,那就可以可以判断可以复用了,返回existing

而在多节点更新的时候,key的作用则更加重要,React 会通过遍历新旧数据,数组和链表来通过按个判断它们的key和 type 来决定是否复用。

所以我们需要合理的使用key来加快diff算法的比对和fiber的复用。

那么如何合理使用key呢。

其实很简单,只需要每一次设置的值和我们的数据一直就可以了。不要使用数组的下标,这种key和数据没有关联,我们的数据发生了更新,结果 React 还指望着复用。

还有哪些工具可以提升性能呢?

实际的开发中还有其他的很多场景需要进行优化:

  • 频繁输入或者滑动滚动的防抖节流
  • 针对大数据展示的虚拟列表,虚拟表格
  • 针对大数据展示的时间分片 等等等等 后面再补充吧!

到此这篇关于React 性能优化方法总结的文章就介绍到这了,更多相关React 性能优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React 首页加载慢问题性能优化案例详解

    学习了一段时间React,想真实的实践一下.于是便把我的个人博客网站进行了重构.花了大概一周多时间,网站倒是重构的比较成功,但是一上线啊,那个访问速度啊,是真心慢,慢到自己都不能忍受,那么小一个网站,没几篇文章,慢成那样,不能接受.我不是一个追求完美的人,但这样可不行.后面大概花了一点时间进行性能的研究.才发现慢是有原因的. React这类框架? 目前主流的前端框架React.Vue.Angular都是采用客户端渲染(服务端渲染暂时不在本文的考虑范围内).这当然极大的减轻了服务器的压力.相对的浏

  • 详解使用React.memo()来优化函数组件的性能

    React核心开发团队一直都努力地让React变得更快.在React中可以用来优化组件性能的方法大概有以下几种: 组件懒加载(React.lazy(...)和<Suspense />) Pure Component shouldComponentUpdate(...){...}生命周期函数 本文还会介绍React16.6加入的另外一个专门用来优化函数组件(Functional Component)性能的方法: React.memo. 无用的渲染 组件是构成React视图的一个基本单元.有些组件

  • 浅谈React组件之性能优化

    高德纳: "我们应该忘记忽略很小的性能优化,可以说97%的情况下,过早的优化是万恶之源,而我们应该关心对性能影响最关键的另外3%的代码." 不要将性能优化的精力浪费在对整体性能提高不大的代码上,而对性能有关键影响的部分,优化并不嫌早.因为,对性能影响最关键的部分,往往涉及解决方案核心,决定整体的架构,将来要改变的时候牵扯更大. 1. 单个React组件的性能优化 React利用Virtual DOM来提升渲染性能,虽然每一次页面更新都是最组件的从新渲染,但是并不是将之前的渲染内容全部抛

  • react性能优化达到最大化的方法 immutable.js使用的必要性

    一行代码胜过千言万语.这篇文章呢,主要讲述我一步一步优化react性能的过程,为什么要用immutable.js呢.毫不夸张的说.有了immutable.js(当然也有其他实现库)..才能将react的性能发挥到极致!要是各位看官用过一段时间的react,而没有用immutable那么本文非常适合你.那么我开始吧! 1.对于react的来说,如果父组件有多个子组件 想象一下这种场景,一个父组件下面一大堆子组件.然后呢,这个父组件re-render.是不是下面的子组件都得跟着re-render.可

  • React性能优化系列之减少props改变的实现方法

    React性能优化的一个核心点就是减少render的次数.如果你的组件没有做过特殊的处理(SCU -- shouldComponentUpdate或使用PureComponent),那每次父组件render时,子组件就会跟着一起被重新渲染.通常一个复杂的子组件都会进行一些优化,比如:SCU 使用PureComponent组件.对于SCU基本上进行的也都是浅比较,深比较的代价太高. 对于这些被优化的子组件,我们要减少一些不必要的props改变:比如事件绑定.对于那些依赖于配置项的组件,我们更是减少

  • 浅谈react性能优化的方法

    React性能优化思路 软件的性能优化思路就像生活中去看病,大致是这样的: 使用工具来分析性能瓶颈(找病根) 尝试使用优化技巧解决这些问题(服药) 使用工具测试性能是否确实有提升(疗效确认) 初识react只是为了尽快完成项目,后期进行代码审查时候发现有很多地方需要优化,因此做了个小结. Code Splitting shouldComponentUpdate避免重复渲染 使用不可突变数据结构 组件尽可能的进行拆分.解耦 列表类组件优化 bind函数优化 不要滥用props ReactDOMSe

  • React函数式组件的性能优化思路详解

    优化思路 主要优化的方向有2个: 减少重新 render 的次数.因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 reconction. 减少计算的量.主要是减少重复计算,对于函数式组件来说,每次 render 都会重新从头开始执行函数调用. 在使用类组件的时候,使用的 React 优化 API 主要是:shouldComponentUpdate和 PureComponent 那么在函数式组件中,我们怎么做性能

  • React 性能优化方法总结

    目录 前言 为什么页面会出现卡顿的现象? React 到底是在哪里出现了卡顿? React 有哪些场景会需要性能优化? 一:父组件刷新,而不波及子组件. 第一种:使用 PureComponent 第三种:函数组件如何判断props的变化的更新呢? 使用 React.memo函数 使用 React.useMemo来实现对子组件的缓冲 一:组件自己控制自己是否刷新 三:减少波及范围,无关刷新数据不存入state中 场景一:无意义重复调用setState,合并相关的state 场景二:和页面刷新没有相

  • React 性能优化之非必要的渲染问题解决

    目录 1. 非必要组件渲染 2. 解决方案之 shouldComponentUpdate 3. 解决方案之 PureComponent 4. 解决方案之 React.memo 5. useMemo 和 useCallback 1. 非必要组件渲染 在 React 工程中,在改变 React 状态时,我们希望对整个页面的影响越小越好.然而实际情况是更改掉某些属性之后,除了会导致组件本身的重新渲染,也可能会导致其相关的组件也发生重新渲染.请看下面的例子: 新建一对父子组件 // 父组件: impor

  • SQL性能优化方法及性能测试

    目录 笛卡尔连接 分页limit的sql优化的几种方法 count 优化方案 笛卡尔连接 例1: 没有携带on的条件字句,此条slq查询的结构集等价于,a表包含的条数*b表包含的乘积: select * from table a cross join table b; 例2:拥有携带on字句的sql,等价于inner join: select * from table a cross join table b on a.id=b.id; 分页limit的sql优化的几种方法 规则;表包含的数据较

  • react性能优化useMemo与useCallback使用对比详解

    目录 引言 对比 useMemo useCallback 引言 在介绍一下这两个hooks的作用之前,我们先来回顾一下react中的性能优化.在hooks诞生之前,如果组件包含内部state,我们都是基于class的形式来创建组件.当时我们也知道,react中,性能的优化点在于: 调用setState,就会触发组件的重新渲染,无论前后的state是否不同 父组件更新,子组件也会自动的更新 基于上面的两点,我们通常的解决方案是:使用immutable进行比较,在不相等的时候调用setState:在

  • React性能优化的实现方法详解

    目录 前言 遍历视图key使用 React.memo缓存组件 React.useCallback让函数保持相同的引用 避免使用内联对象 使用React.useMemo缓存计算结果或者组件 使用React.Fragment片段 组件懒加载 通过 CSS 加载和卸载组件 变与不变的地方做分离 总结 前言 想要写出高质量的代码,仅仅靠框架底层帮我们的优化还远远不够,在编写的过程中,需要我们自己去使用提高的 api,或者根据它底层的原理去做一些优化,以及规范. 相比于 Vue ,React 不会再框架源

  • 正则表达式性能优化方法(高效正则表达式书写)

    这里说的正则表达式优化,主要是针对目前常用的NFA模式正则表达式,详细可以参考:正则表达式匹配解析过程探讨分析(正则表达式匹配原理).从上面例子,我们可以推断出,影响NFA类正则表达式(常见语言:GNU Emacs,Java,ergp,less,more,.NET语言, PCRE library,Perl,PHP,Python,Ruby,sed,vi )其实主要是它的"回溯",减少"回溯"次数(减少循环查找同一个字符次数),是提高性能的主要方法. 我们来看个例子:

  • MySQL Index Condition Pushdown(ICP)性能优化方法实例

    一 概念介绍 Index Condition Pushdown (ICP)是MySQL 5.6 版本中的新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式. a 当关闭ICP时,index 仅仅是data access 的一种访问方式,存储引擎通过索引回表获取的数据会传递到MySQL Server 层进行where条件过滤. b 当打开ICP时,如果部分where条件能使用索引中的字段,MySQL Server 会把这部分下推到引擎层,可以利用index过滤的where条件在存储引擎层进行

随机推荐