React性能优化
memo: 包装组件
useMemo :包装传参(除函数)
useCallback:包装函数传递
一、 组件的优化(没有任何传值,单纯的调用)
例:
import React, { useState } from 'react'
import Child from './child'
export default function Parent(props: any) {
const [num, setNum] = useState(0)
const handleClick = () => {
setNum(num + 1)
}
return (
<div>
<h2>{num}</h2>
<button onClick={handleClick}>更改num</button>
{/* 引用子组件 */}
<Child />
</div>
)
}
子组件:
export default function Child(props: any) {
console.info('子组件渲染了')
return <div>我是子组件</div>
}
调用结果,子组件跟随父组件渲染了,造成了不必要的性能浪费
优化组件的渲染:
使用react的memo来控制子组件的渲染(原理: 对子组件的props进行浅比较)
改造后的组件展示:
import React, { useState } from 'react'
import React, { useState, memo } from 'react' // 也可以直接导入memo
import Child from './child'
const MemoChild = React.memo(Child) // 新增代码,使用memo处理子组件
// 或者
const MemoChild memo(Child) // 新增代码,使用memo处理子组件
export default function Parent(props: any) {
const [num, setNum] = useState(0)
const handleClick = () => {
setNum(num + 1)
}
return (
<div>
<h2>{num}</h2>
<button onClick={handleClick}>更改num</button>
{/* 引用子组件 */}
{/* <Child /> */}
{/* 新增代码 */}
<MemoChild />
</div>
)
}
此时子组件就不会跟随父组件的渲染而渲染
二、 子组件传入了处理函数
单纯的使用memo依然会使子组件多次渲染,这是就是用hooks中的useCallback
因为父组件的渲染使函数再次注册了一次。所以导致传入子组件的props改变加粗样式了
分析原因: 首先一个组件重新渲染,一般是三种情况导致的:
1.组件自己的状态改变了
2.父组件重新渲染,但父组件的 props 没有改变
3.父组件重新渲染,父组件传递的 props 改变
组件自己的状态改变了 父组件重新渲染,但父组件的 props 没有改变
父组件重新渲染,父组件传递的 props 改变 很明显,第一种不是,因为子组件并没有任何状态。
第二种,已经用 React.memo 优化掉了,所以也不是。
那说明就是第三种, 传递的 props 改了。
// 新增引入 useCallback
import React, { useState, useCallback } from 'react'
import Child from './child'
const MemoChild = React.memo(Child)
export default function Parent(props: any) {
const [num, setNum] = useState<number>(0)
const handleClick = () => {
setNum(num + 1)
}
// 修改代码
// 通过 useCallback 进行记忆 handleChange, 并将记忆的 handleChange 传递给 MemoChild
const memoizedCallback = useCallback(() => {
console.info(2323)
},[])
return (
<div>
<h2>{num}</h2>
<button onClick={handleClick}>更改num</button>
{/* 引用子组件 */}
<MemoChild handleChange={memoizedCallback} />
</div>
)
}
三、子组件接收参数(对象形式传输 )
因为对props 浅比较,所以当以对象像是传输时,浅比较失效。导致子组件渲染
所以使用useMemo 来处理传参
import React, { useState,useMemo } from 'react'
import Child from './child'
const MemoChild = React.memo(Child)
export default function Parent(props: any) {
const [num, setNum] = useState<number>(0)
const handleClick = () => {
setNum(num + 1)
}
return (
<div>
<h2>{num}</h2>
<button onClick={handleClick}>更改num</button>
{/* 采用 useMemo */}
<MemoChild person={useMemo(()=>({name:"张三"}),[])} />
</div>
)
}
四、综合所有的情况
import React, { useState,useMemo,useCallback,memo } from 'react'
import Child from './child'
const MemoChild = memo(Child) // 包装子组件
export default function Parent(props: any) {
const [num, setNum] = useState<number>(0)
const handleClick = () => {
setNum(num + 1)
}
const memoizedCallback = useCallback(() => {
console.log(4444)},[]) // 包装函数
return (
<div>
<h2>{num}</h2>
<button onClick={handleClick}>更改num</button>
{/* 采用 useMemo */}
<MemoChild person={useMemo(()=>({name:"张三"}),[])} onChang={memoizedCallback} />
</div>
)
}