React性能优化的8种方式了解一下?

react凭借virtual DOM和diff算法拥有高效的性能,除此以外也有不少其余的方法和技巧能够进一步提高react性能,在本文中我将列举出可有效提高react性能的几种方法,帮助咱们改进react代码,提高性能。可是咱们没必要必定要在项目中使用这些方法,可是咱们有必要知道如何使用这些方法。

使用React.Memo来缓存组件

提高应用程序性能的一种方法是实现memoization。Memoization是一种优化技术,主要经过存储昂贵的函数调用的结果,并在再次发生相同的输入时返回缓存的结果,以此来加速程序。
父组件的每次状态更新,都会致使子组件从新渲染,即便传入子组件的状态没有变化,为了减小重复渲染,咱们可使用React.memo来缓存组件,这样只有当传入组件的状态值发生变化时才会从新渲染。若是传入相同的值,则返回缓存的组件。示例以下:javascript

export default React.memo((props) => {
  return (
    <div>{props.value}</div>  
  )
});
复制代码

使用useMemo缓存大量的计算

有时渲染是不可避免的,但若是您的组件是一个功能组件,从新渲染会致使每次都调用大型计算函数,这是很是消耗性能的,咱们可使用新的useMemo钩子来“记忆”这个计算函数的计算结果。这样只有传入的参数发生变化后,该计算函数才会从新调用计算新的结果。
经过这种方式,您可使用从先前渲染计算的结果来挽救昂贵的计算耗时。整体目标是减小JavaScript在呈现组件期间必须执行的工做量,以便主线程被阻塞的时间更短。java

// 避免这样作
function Component(props) {
  const someProp = heavyCalculation(props.item);
  return <AnotherComponent someProp={someProp} /> 
}
  
// 只有 `props.item` 改变时someProp的值才会被从新计算
function Component(props) {
  const someProp = useMemo(() => heavyCalculation(props.item), [props.item]);
  return <AnotherComponent someProp={someProp} /> 
}
复制代码

使用React.PureComponent , shouldComponentUpdate

父组件状态的每次更新,都会致使子组件的从新渲染,即便是传入相同props。可是这里的从新渲染不是说会更新DOM,而是每次都会调用diif算法来判断是否须要更新DOM。这对于大型组件例如组件树来讲是很是消耗性能的。
在这里咱们就可使用React.PureComponent , shouldComponentUpdate生命周期来确保只有当组件props状态改变时才会从新渲染。以下例子:react

export default function ParentComponent(props) {
  return (
    <div>
      <SomeComponent someProp={props.somePropValue}
    <div>
      <AnotherComponent someOtherProp={props.someOtherPropValue} />
    </div>
   </div>
 )
}

export default function SomeComponent(props) {
  return (
    <div>{props.someProp}</div>  
  )
}

// 只要props.somePropValue 发生变化,不论props.someOtherPropValue是否发生变化该组件都会发生变化
export default function AnotherComponent(props) {
  return (
    <div>{props.someOtherProp}</div>  
  )
}
复制代码

咱们可使用React.PureComponent 或shouldComponentUpdate 进行以下优化:git

// 第一种优化
class AnotherComponent extends React.PureComponent {
  render() {
    return <div>{this.props.someOtherProp}</div>   
  }
}

//第二种优化
class AnotherComponent extends Component {
  shouldComponentUpdate(nextProps) {
    return this.props !== nextProps
  }
  render() {
    return <div>{this.props.someOtherProp}</div>   
  }
}
复制代码


PureComponent会进行浅比较来判断组件是否应该从新渲染,对于传入的基本类型props,只要值相同,浅比较就会认为相同,对于传入的引用类型props,浅比较只会认为传入的props是否是同一个引用,若是不是,哪怕这两个对象中的内容彻底同样,也会被认为是不一样的props。
须要注意的是在对于那些能够忽略渲染时间的组件或者是状态一直变化的组件则要谨慎使用PureComponent,由于进行浅比较也会花费时间,这种优化更适用于大型的展现组件上。大型组件也能够拆分红多个小组件,并使用memo来包裹小组件,也能够提高性能。github

避免使用内联对象

使用内联对象时,react会在每次渲染时从新建立对此对象的引用,这会致使接收此对象的组件将其视为不一样的对象,所以,该组件对于prop的浅层比较始终返回false,致使组件一直从新渲染。
许多人使用的内联样式的间接引用,就会使组件从新渲染,可能会致使性能问题。为了解决这个问题,咱们能够保证该对象只初始化一次,指向相同引用。另一种状况是传递一个对象,一样会在渲染时建立不一样的引用,也有可能致使性能问题,咱们能够利用ES6扩展运算符将传递的对象解构。这样组件接收到的即是基本类型的props,组件经过浅层比较发现接受的prop没有变化,则不会从新渲染。示例以下:算法

// Don't do this!
function Component(props) {
  const aProp = { someProp: 'someValue' }
  return <AnotherComponent style={{ margin: 0 }} aProp={aProp} />  
}

// Do this instead :)
const styles = { margin: 0 };
function Component(props) {
  const aProp = { someProp: 'someValue' }
  return <AnotherComponent style={styles} {...aProp} />  
}
复制代码

避免使用匿名函数

虽然匿名函数是传递函数的好方法(特别是须要用另外一个prop做为参数调用的函数),但它们在每次渲染上都有不一样的引用。这相似于上面描述的内联对象。为了保持对做为prop传递给React组件的函数的相同引用,您能够将其声明为类方法(若是您使用的是基于类的组件)或使用useCallback钩子来帮助您保持相同的引用(若是您使用功能组件)。
固然,有时内联匿名函数是最简单的方法,实际上并不会致使应用程序出现性能问题。这多是由于在一个很是“轻量级”的组件上使用它,或者由于父组件实际上必须在每次props更改时从新渲染其全部内容。所以不用关心该函数是不是不一样的引用,由于不管如何,组件都会从新渲染。浏览器

// 避免这样作
function Component(props) {
  return <AnotherComponent onChange={() => props.callback(props.id)} />  
}

// 优化方法一
function Component(props) {
  const handleChange = useCallback(() => props.callback(props.id), [props.id]);
  return <AnotherComponent onChange={handleChange} />  
}

// 优化方法二
class Component extends React.Component {
  handleChange = () => {
   this.props.callback(this.props.id) 
  }
  render() {
    return <AnotherComponent onChange={this.handleChange} />
  }
}
复制代码

延迟加载不是当即须要的组件

延迟加载实际上不可见(或不是当即须要)的组件,React加载的组件越少,加载组件的速度就越快。所以,若是您的初始渲染感受至关粗糙,则能够在初始安装完成后经过在须要时加载组件来减小加载的组件数量。同时,这将容许用户更快地加载您的平台/应用程序。最后,经过拆分初始渲染,您将JS工做负载拆分为较小的任务,这将为您的页面提供响应的时间。这可使用新的React.Lazy和React.Suspense轻松完成。缓存

// 延迟加载不是当即须要的组件
const MUITooltip = React.lazy(() => import('@material-ui/core/Tooltip'));
function Tooltip({ children, title }) {
  return (
    <React.Suspense fallback={children}> <MUITooltip title={title}> {children} </MUITooltip> </React.Suspense> ); } function Component(props) { return ( <Tooltip title={props.title}> <AnotherComponent /> </Tooltip> ) } 复制代码

调整CSS而不是强制组件加载和卸载

渲染成本很高,尤为是在须要更改DOM时。每当你有某种手风琴或标签功能,例如想要一次只能看到一个项目时,你可能想要卸载不可见的组件,并在它变得可见时将其从新加载。若是加载/卸载的组件“很重”,则此操做可能很是消耗性能并可能致使延迟。在这些状况下,最好经过CSS隐藏它,同时将内容保存到DOM。
尽管这种方法并非万能的,由于安装这些组件可能会致使问题(即组件与窗口上的无限分页竞争),但咱们应该选择在不是这种状况下使用调整CSS的方法。另一点,将不透明度调整为0对浏览器的成本消耗几乎为0(由于它不会致使重排),而且应尽量优先于更该visibility 和 display。
有时在保持组件加载的同时经过CSS隐藏多是有益的,而不是经过卸载来隐藏。对于具备显著的加载/卸载时序的重型组件而言,这是有效的性能优化手段。性能优化

// 避免对大型的组件频繁对加载和卸载
function Component(props) {
  const [view, setView] = useState('view1');
  return view === 'view1' ? <SomeComponent /> : <AnotherComponent />  
}

// 使用该方式提高性能和速度
const visibleStyles = { opacity: 1 };
const hiddenStyles = { opacity: 0 };
function Component(props) {
  const [view, setView] = useState('view1');
  return (
    <React.Fragment>
      <SomeComponent style={view === 'view1' ? visibleStyles : hiddenStyles}>
      <AnotherComponent style={view !== 'view1' ? visibleStyles : hiddenStyles}>
    </React.Fragment>
  )
}
复制代码

使用React.Fragment避免添加额外的DOM

有些状况下,咱们须要在组件中返回多个元素,例以下面的元素,可是在react规定组件中必须有一个父元素。函数

<h1>Hello world!</h1>
            <h1>Hello there!</h1>
            <h1>Hello there again!</h1>
复制代码

所以你可能会这样作,可是这样作的话即便一切正常,也会建立额外的没必要要的div。这会致使整个应用程序内建立许多无用的元素:

function Component() {
        return (
            <div> <h1>Hello world!</h1> <h1>Hello there!</h1> <h1>Hello there again!</h1> </div>
        )
}
复制代码

实际上页面上的元素越多,加载所需的时间就越多。为了减小没必要要的加载时间,咱们可使React.Fragment来避免建立没必要要的元素。

function Component() {
        return (
            <React.Fragment> <h1>Hello world!</h1> <h1>Hello there!</h1> <h1>Hello there again!</h1> </React.Fragment> ) } 复制代码

总结

咱们文中列出的基本上是React内部提供的性能优化方法,这些方法能够帮助React更好地执行,并无列出例如Immutable.js第三方工具库的优化方法。其实性能优化的方法有不少,但正如上面所说的,合适的方法也要在合适的场景下使用,过分的使用性能优化反而会得不偿失。

参考连接

最后

原文在这里:gitHub 若有遗漏,还请指正!!

若是以为对您有帮助!请别忘记点个赞或者关注哦!您的关注将是我前进的动力!!冲鸭!!!
相关文章
相关标签/搜索