本文已参与「新人创作礼」活动,一起开启掘金创作之路
REACT性能优化
react常见性能优化方法
1、组件按需加载 组件按需加载又可以分为懒加载、懒渲染、虚拟列表三类
懒加载
react懒加载主要是Suspense实现
参考文档:www.jb51.net/article/262…
import React, {Suspense, Lazy} from "react";
let flag = true
// 使用lazy做动态导入,并做错误处理
const ChildApp = Lazy(() => {
return new Promise((resolve,reject) => {
if(flag){
resolve(import "./ChildrenApp")
}else{
reject("somthing wrong")
}
})
})
const APP = () => {
return (
<div>
<Suspense fallback="loading...">
<Children />
</suspense>
</div>
)
}
懒渲染
react中使用react-visibility-obserreact-visibility-observe进行监听
import VisibilityObserver,{useVisibilityObserver} from "react-visibility-observer";
const VisibilityChildren = (callback, children) => {
const { isVisible } = useVisibilityObserver()
useEffect(() => {
if(isvisibility){
callback(isvisibility)
}
},[callback,isvisible])
return <Children />
}
const lazyRender = () => {
const [isRendered,setIsRendered] = useState(false)
if(!isRendered){
return (
<VisibilityObserver>
<VisibilityChildren
callback={(isvisible) => {
if(isvisible) {
setIsRendered(true)
}
}}
>
<span />
</VisibilityChildren>
</VisibilityObserver>
)
}
return (
<div>到可视区域才渲染</div>
)
}
2、跳过不必要的组件更新
React.PureComponent和React.memo实现控制子组件更新次数 在react中当父组件的发生状态更新进行render时,即使父组件传给子组件的state和props都没有变化,组件同样也会rerender, React.pureComponent和React.memo的作用就是阻止这种不必要的子组件的渲染
//React.PureComponent主要搭配类组件 //React.memo搭配函数组件
const App = () => {
const [list,setList] = useState([{
title:"React",
level:"six",
},
{
title:"vue",
level:"five",
}])
useEffect(() => {
setTimeout(() => {
settList([{
title:"React",
level:"six",
},
{
title:"vue",
level:"five",
}])
},1000)
},[])
return (
<div>
{
list.map(item => {
// memo进行的是浅比较,当传值为数组或者对象时,仍然会render字组件
<Children data={item} />
//传值改为浅层值
<Children {...item}>
})
}
</div>
)
}
// Children 会重复render
const Children = (props) => {
return (
<div>{props.data.title} : {props.data.level}</div>
)
}
// 使用memo
const Children = React.memo((props) => {
return (
<div>{props.data.title} : {props.data.level}</div>
)
})
3、使用useCallback和useMemo稳定状态
useCallback的重要作用是当父组件的函数作为子组件的回调时,每当父组件更新,会重新创建该函数,所以子组件检测到函数变化会rerender,而实际情况,当函数没有变化时,且依赖没有变化,子组件是不需要rerender的,所以useCallback的作用就是,当依赖没有变化时,给子组件传递一个同样的值,使子组件不更新
const Child = ({
reRenderEvent,
noReRenderEvent
}) => {
console.log("子组件加载")
return <div>
// 点击时子组件会rerender
<a onClick={reRenderEvent}>我是子组件点击事件,会导致子组件渲染</a>
<br />
// 子组件不会rerender
<a onClick={noReRenderEvent}>我是子组件点击事件,不会导致子组件渲染</a>
</div>
}
export const Parent = () => {
const [count,setCount] = useState(0)
const reRenderEvent = () => {
console.log('count',count)
setCount(count + 1)
}
const noReRenderEvent = useCallback(() => {
console.log('count',count)
setCount(count + 1)
},[])
return (
<div>
<p>I am parent component</p>
<Child
reRenderEvent = {reRenderEvent}
noReRenderEvent = {noReRenderEvent}
/>
</div>
)
}
useMemo的使用场景是,当组件更新时,某些计算量比较大的值很有可能被重新计算,useMemo用来缓存计算值,避免重复计算,
useMemo还可以直接返回dom,当返回dom时,在依赖不变的情况下将跳过render阶段
export const Memo = () => {
const [count,setCount] = useState(0)
const [sum,setSum] = useState(0)
// count 和sum改变都会触发计算
const countCaculate = (() => {
console.log("caculation of the count")
})()
// 只有依赖sum改变才会触发计算
const sumCaculate = useMemo(() => {
console.log("caculation of the sum")
},[sum])
// 直接返回dom
const memoDom = useMemo(() => {
return <p>直接返回dom</p>
},[])
return (
<div>
<button onClick={() => {
setCount(count + 1)
}}>click me count add one</button>
<br />
<button onClick={() => {
setSum(sum + 1)
}}>click me sum add one</button>
</div>
)
}