React 性能优化

求上进的人,不要总想着靠谁,人都是自私的,自己才是最靠得住的人。

1. shouldComponentUpdate

React 手动优化,控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下,需要进行优化。

2. PureComponent

React 自动优化,PureComponent 会帮你比较新 props 跟旧的 props,新的 state 和老的 state(值相等,或者对象含有相同的属性、且属性值相等),决定 shouldComponentUpdate 返回 true 或者 false,从而决定要不要呼叫 render function。

注意:如果你的 state 或 props『永远都会变』,那 PureComponent 并不会比较快,因为 shallowEqual 也需要花时间,比如倒计时功能,这就不适合使用 Pure Component 了。

import React, { Component, PureComponent } from 'react'

export default class App extends PureComponent {
  render() {
    return (
      <div>App</div>
    )
  }
}

3. 缓存技术

React.Component 是使用 ES6 classes 方式定义 React 组件的基类:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

PureComponent 和 memo 仅作为性能优化的方式而存在。但请不要依赖它来“阻止”渲染,因为这会产生 bug。PureComponnet 和 memo 都是通过对 props 值的浅比较来决定该组件是否需要更新的。

3.1 PureComponent (类组件)

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 props 和 state 的方式来实现了该函数。
如果赋予 React 组件相同的 props 和 state,render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。

3.2 memo(函数式组件)

函数组件缓存 memo,为啥起 memo 这个名字?在计算机领城,记记化是一种主要用来提高计算机程序速度的优化技术方案。它将开销较大的函数调用的返回结果存储起来,当同样的输入再次发生时,则返回缓存好的数据,以此提升运算效率。

React.memo 为高阶组件。它与 React.PureComponent 非常相似,但只适用于函数组件,而不适用 class 组件。

const MyComponent = function MyComponent(props) {
  /* 使用 props 渲染 */
};
export default React.memo(MyComponent)

如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果,即组件仅在它的 props 发生改变的时候进行重新渲染。通常来说,在组件树中 React 组件,只要有变化就会走一遍渲染流程。但是 React.memo(),我们可以仅仅让某些组件进行渲染。

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

function MyComponent(props) {
  /* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
  
}
export default React.memo(MyComponent, areEqual);

示例:

// 子组件代码:
import React, { memo } from 'react';
const Child = ()=>{
	console.log("2. 子组件渲染了")
	return (<div>子组件</div>)
}
export default Child

// 父组件代码:
import React, { memo } from 'react';
import Child from './Child.jsx'
const Father = ()=>{
	const [name,setName]=React.useState('');
	console.log("1. 父组件渲染了")
	return (<div>
		/* 在input框中输入内容,会走setName导致App组件重新渲染,但是子组件Child也会进行渲染。 */
		父组件:<input type="text" value={name} onChange={ev=>setName(ev.target.value)} />
		<Child />
	</div>)
}
// 子组件代码:
import React, { memo } from 'react';
const Child = ()=>{
	console.log("2. 子组件渲染了")
	return (<div>子组件</div>)
}
export default memo(Child)
// 父组件代码:
import React, { memo } from 'react';
import Child from './Child.jsx'
const Father = ()=>{
	const [name,setName]=React.useState('');
	console.log("1. 父组件渲染了")
	return (<div>
		/* 解决:子组件使用memo包起来 */
		父组件:<input type="text" value={name} onChange={ev=>setName(ev.target.value)} />
		<Child />
	</div>)
}

4. 懒加载

4.1 React 懒加载

React 中懒加载 Lazy 与 Suspense 需要搭配使用。

React.lazy 定义:

React.1azy 函数能让你像渲染常规组件一样处理动态引入的组件。其实就是懒加载。

为什么代码要分割?

当你的程序越来越大,代码量越来越多。一个页面上堆积了很多功能,也许有些功能很可能都用不到,但是一样下载加载到页面上,所以这里面肯定有优化空间。就如图片懒加载的理论。

实现原理?

当 webpack 解析到该语法时,它会自动地开始进行代码分割(Code Splitting),分割成一个文件,当使用到这个文件的时候这段代码才会被异步加载。

解决方案?

在 React.1azy 和常用的三方包 react-1oadab1e(路由懒加载),都是使用了这个原理,然后配合 webpack 进行代码打包拆分达到异步加载,这样首屏渲染的速度将大大的提高。由于 React.1azy 不支持服务端渲染,所以这时候 react-1oadable 就是不错的选择。

4.2 Lazy 和 Suspense 使用

// 当使用到的时候才进行导入
const NewComponent = React.lazy(()=>import('./component/NewComponent'))

<Suspense fallback={<div>正在加载中</div>}>
  <NewComponent></NewComponent>
<Suspense>

4.3 第三方库 react-loadable 使用

https://blog.csdn.net/luofeng457/article/details/107023328

posted @ 2023-12-04 19:28  背包の技术  阅读(496)  评论(0)    收藏  举报