import{ useState }from"react";constApp=()=>{let[color, setColor]=useState("red");return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/><ExpensiveTree/></div>);};constExpensiveTree=()=>{let now =performance.now();while(performance.now()- now <100){// 延迟}console.log('render');return<p>I am a very slow component tree.</p>;};
input例子
很明显,每当我们在 input 里面输入内容,console.log('render')都会输出,因为 color 的状态发生了改变,也间接说明了其与 props 完全没有关系
这样的开销是很不合理的,我们接下来会优化它。
性能优化
方式一: State 抽离
我们知道 react 是单向数据流,因此我们只需要将 State 的抽离出来即可。
javascript
import{ useState }from"react";constApp=()=>{return(<div><Input/><ExpensiveTree/></div>);};constExpensiveTree=()=>{let now =performance.now();while(performance.now()- now <100){// 延迟}console.log("render");return<p>I am a very slow component tree.</p>;};constInput=()=>{let[color, setColor]=useState("red");return<input value={color} onChange={(e)=>setColor(e.target.value)}/>;}
import{ memo, useState }from"react";constApp=()=>{let[color, setColor]=useState("red");return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/><ExpensiveTree/></div>);};constExpensiveTree=memo(()=>{let now =performance.now();while(performance.now()- now <100){// 延迟}return<p>I am a very slow component tree.</p>;})
方式三: react children
因为 App 并没有发生状态改变所以 ExpensiveTree 避免了重复渲染
javascript
import{FC,PropsWithChildren, useState }from"react";constApp=()=>{return(<ColorWrapper><ExpensiveTree/></ColorWrapper>);};constColorWrapper:FC<PropsWithChildren>=({ children })=>{let[color, setColor]=useState("red");return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/>{children}</div>);};constExpensiveTree=()=>{let now =performance.now();while(performance.now()- now <100){// 延迟}return<p>I am a very slow component tree.</p>;};
import{ memo, useMemo, useState }from"react";constApp=()=>{let[color, setColor]=useState("red");return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/>{useMemo(()=>(<ExpensiveTree/>),[])}</div>);};constExpensiveTree=()=>{let now =performance.now();while(performance.now()- now <100){// 延迟}return<p>I am a very slow component tree.</p>;};
useCallback
我们先看如下例子
javascript
import{FC, memo, useState }from"react";constApp=()=>{let[color, setColor]=useState("red");constfn=()=>{console.log('hahaha');}return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/><ExpensiveTree fn={fn}/></div>);};constExpensiveTree:FC<{fn:()=>void}>=memo(({fn})=>{let now =performance.now();while(performance.now()- now <100){// 延迟}console.log('render');// 依旧会被不断更新return<p>I am a very slow component tree.</p>;})
import{FC, memo, useCallback, useState }from"react";constApp=()=>{let[color, setColor]=useState("red");const fn =useCallback(()=>{console.log('hahaha');},[])return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/><ExpensiveTree fn={fn}/></div>);};constExpensiveTree:FC<{fn:()=>void}>=memo(({fn})=>{let now =performance.now();while(performance.now()- now <100){// 延迟}console.log('render');return<p>I am a very slow component tree.</p>;})
import{FC, memo, useMemo, useState }from"react";constApp=()=>{let[color, setColor]=useState("red");const fn =useMemo(()=>{return()=>console.log("hahaha");},[]);return(<div><input value={color} onChange={(e)=>setColor(e.target.value)}/><ExpensiveTree fn={fn}/></div>);};constExpensiveTree:FC<{fn:()=>void}>=memo(({ fn })=>{let now =performance.now();while(performance.now()- now <100){// 延迟}console.log("render");return<p>I am a very slow component tree.</p>;});