1.API useCallback useMemo memo
先回顾一下react 执行的流程
react 是一个从虚拟DOM(Firber) 到真实DOM 的转化
React 页面渲染存在两个阶段:
调度阶段(reconciliation):更新数据生成新的 Virtual DOM,然后通过 Diff 算法,快速找出需要更新的元素,放到更新队列中去,得到新的更新队列。
渲染阶段(commit):遍历更新队列,将其所有的变更一次性更新到DOM上。
由上会引出一个问题,哪些会引起视图的更新并执行diff算法?
useState,props,useContext会引起视图的更新
useState,useContext就不讨论,主讲3个api用到的部分
对props 的比较
1.全等的进行比较(react默认)
2.不全等的进行比较(useMemo memo useCallback 来触发)
举个关于react默认比较的例子
import './App.css'
import { memo, useState } from 'react'
const A = () => {
console.log('A')
return <div>这是A组件</div>
}
function App () {
const [number, setNumber] = useState(0)
return (
<>
<div>APP</div>
<div>number的值是{number}</div>
<button onClick={() => {
setNumber((old) => old + 1)
}}>加1</button>
<A></A>
</>
)
}
export default App
每点一次加1 的 按钮,控制台都会打印一次’A’
接下来修改A组件的代码
const A = memo(() => {
console.log('A')
return <div>这是A组件</div>
})
点击加1按钮,控制台不打印’A’
这是为啥呢?
我来解释一下:
实际上A组件的props是{},但是{}==={}不是全等的,判断结果为false,就会重新执行这部分代码,现在在外面套上memo方法,从全等比较改为不全等比较,这个props值比较为true,这部分代码不触发diff算法,也就不更新
讲第二个例子
子组件A 传入一个参数
<A appState={setNumber}></A>// 不触发更新
但是假如传入的参数值修改成自己定义的函数,就会触发更新
const dom = () => {
console.log('dom')
}
<A appState={dom}></A> // 触发更新
现在把新定义的函数用useCallback 包裹一下,就不会触发更新,这又是为什么呢?
const dom = useCallback(() => {
console.log('dom')
}, [])
原因:可以把App看成一个构造函数,每一次执行就会产生一个闭包,dom函数2次执行在不同的闭包中,所以判断的时候,就会触发更新,加上useCallback函数,相当于把传入的函数放在缓存中,props是从缓存中取,因为地址是同一个地址,一直没改变就不会触发更新
2.页面结构
下面讲到页面结构(把不变的组件和变得组件抽离出来),就不会触发更新,点击按钮,只会打印’B’,说明只有B组件更新
import './App.css'
import { memo, useState, useCallback } from 'react'
const A = memo(({ number }) => {
console.log('A')
return <div>这是A组件</div>
})
const B = () => {
console.log('B')
const [number, setNumber] = useState(0)
return (
<>
<div>number的值是{number}</div>
<button onClick={() => {
setNumber((old) => old + 1)
}}>加1</button>
</>
)
}
function App () {
console.log('App')
const dom = () => {
console.log('dom')
}
return (
<>
<div>APP</div>
<B></B>
<A appState={dom}></A>
</>
)
}
export default App