React性能优化技巧总结
时间:2023-03-12 08:04:54
科技观察
本文将从render函数的角度总结ReactApp的优化技巧。需要提醒的是,本文会涉及到React16.8.2版本的内容(即Hooks),所以请至少了解useState,以保证可食用的效果。正文开始。当我们讨论ReactApp的性能问题时,组件的渲染速度是一个重要的问题。在进入具体的优化建议之前,我们需要了解以下3点:当我们说“渲染”时,我们在说什么?什么时候执行“render”?“渲染”过程中会发生什么?解释渲染函数涉及协调和差异的概念。当然,官方文档在这里。当我们说“渲染”时,我们在说什么?其实写过React的人都会知道这个问题。这里简单介绍一下:在类组件中,我们指的是render方法:classFooextendsReact.Component{render(){return
Foo
;}}在功能组件中,我们指的是功能组件本身:functionFoo(){return
Foo
;}什么时候执行“render”?渲染函数将在两种情况下被调用:1.当状态更新时a.继承自React.Component的class组件更新状态时importReactfrom"react";importReactDOMfrom"react-dom";classAppextendsReact.Component{render(){return
;}}classFooextendsReact.Component{state={count:0};increment=()=>{const{count}=this.state;constnewCount=count<10?count+1:count;this.setState({count:newCount});};render(){const{count}=this.state;console.log("Foorender");return(
{count}
增量);}}constrootElement=document.getElementById("root");ReactDOM.render(
,rootElement);可以看到,代码中的逻辑如果我们点击,计数就会更新,10次之后,会一直保持在10。添加一个console.log以便我们可以知道是否调用了渲染。从执行结果可以知道,即使计数超过10,render还是会被调用。总结:继承React.Component类组件,即使state没变,只要调用setState就会触发render。b.当功能组件更新状态时,我们使用函数来实现相同的组件。当然,因为我们需要状态,所以我们使用useState钩子:{const[count,setCount]=useState(0);functionincrement(){constnewCount=count<10?count+1:count;setCount(newCount);}console.log("Foorender");return(
{count}
增量);}constrootElement=document.getElementById("root");ReactDOM.render(
,rootElement);我们可以注意到,当状态值不再变化时,对渲染的调用停止。总结:对于函数式组件来说,只有当state值发生变化时才会触发render函数的调用。2.当父容器重新渲染时/>
this.setState({name:"App"})}>Changename );}}functionFoo(){console.log("Foorender");return(
Foo
);}constrootElement=document.getElementById("root");ReactDOM.render(
,rootElement);只需单击App组件中的Changename按钮,它就会重新呈现。请注意,无论Foo的实现是什么,Foo都将被重新渲染。总结:无论组件是继承自React.Component的类组件还是函数式组件,一旦父容器重新渲染,都会再次调用组件的render。“渲染”过程中会发生什么?每当调用渲染函数时,都会依次执行两个步骤。这两步非常重要,理解了它们才能知道如何优化ReactApp。Diffing在此步骤中,React将新调用的render函数返回的树与旧版本的树进行比较。这一步对于React决定如何更新DOM是必要的。虽然React使用高度优化的算法执行此步骤,但仍然存在一定的性能开销。协调基于差异的结果,React更新DOM树。由于需要卸载和挂载DOM节点,这一步也有很大的性能开销。开始我们的TipsTip#1:仔细分配状态以避免不必要的渲染调用让我们以下面的例子为例,其中App将渲染两个组件:CounterLabelListimportReact,{useState}from"react";importReactDOMfrom"react-dom";constITEMS=[1,2,3,4,5,6,7,8,9,10,11,12];functionApp(){const[count,setCount]=useState(0);const[items,setItems]=useState(ITEMS);return(
setCount(count+1)}/>