昨天学习了useMemo的使用,我们知道useMemo起到了缓存变量的作用。
而useCallback的作用起到了缓存函数的作用。下面我们来看一下怎么使用以及注意事项。
memo
首先我们先来学习一下memo这个函数,这个函数是从react中直接使用的这个函数是一个包裹函数;
import React, {
memo } from 'react'
它的作用类似class组件中的pureComponent;以及shouldComponentUpdate这个钩子函数的作用。
在function时代,已经没有了pureComponent和shouldComponentUpdate这种东西,而是react提供了React.memo这样的高阶组件,与pureComponent和相似,但是,这个高阶组件并不是适用于class组件,而只为function组件服务。相比于 PureComponent ,React.memo() 可以支持指定一个参数,可以相当于 shouldComponentUpdate 的作用,因此 React.memo() 相对于 PureComponent 来说,用法更加方便。
用法:
const A = memo(function A(props) {
let {
giveSonFun } = props
console.log(giveSonFun, 'giveSonFun')
return (
<>
我是A组件内容
</>
)
})
export default A;
这样一来我们的组件就会自动的根据变量是否变化而从新渲染函数式组件;
当我们将A组件作为子组件的时候,无论父组件谁的状态更新了,它的所有子组件都会自动的进行重新渲染,有时候我们的子组件是完全没有必要重新渲染的,所有我们可以使用这个React.mome组件进行包裹,起到了纯组件(pureComponent)的作用。
useCallback
首先我们看下面的例子,我们用到了useState这个hook:
import './App.css';
import React, {
useState, useMemo, useCallback, memo } from 'react'
function App() {
const [name, setName] = useState("LiuQing")
const a =1
// 类似vue 中的computed 计算属性
// 用于缓存变量
const studyRun = React.useMemo(() => name + 'String', [name])
const changeName = () => {
setName("mynameiszjq" + Math.random())
}
// const giveSonFun = useCallback(() => {
// console.log("子组件执行了函数")
// }, [a])
const giveSonFun = () => {
console.log("子组件执行了函数")
}
return (
<React.Fragment>
<p>studyRun:{
studyRun}</p>
<button onClick={
changeName}>点击更改studyRun</button>
<div style={
{
border: "2px solid #ccc", height: "300px", width: "500px" }}>
我是A组件
<A giveSonFun={
giveSonFun} />
</div>
</React.Fragment>
);
}
const A = memo(function A(props) {
let {
giveSonFun } = props
console.log(giveSonFun, 'giveSonFun')
return (
<>
我是A组件内容
<hr />
<button onClick={
giveSonFun}>点击我执行父组件传入的方法</button>
</>
)
})
export default App;
在上面的例子中我们在APP组件中写个两个giveSonFun 方法,一个是用useCallback包裹的,一个是普通的函数,
我们先使用普通函数,看效果。
页面初始化的时候,打印了一个giveSonFun 函数体,说明我们子组件渲染了一次。
我们开始点击,APP组件中的按钮:
我们点击了几次,子组件A重新render了几次,说明每一次都传入了一个新的函数地址。
我们打开useCallback包裹的函数giveSonFun ,注释掉普通函数giveSonFun ;
import './App.css';
import React, {
useState, useMemo, useCallback, memo } from 'react'
function App() {
const [name, setName] = useState("LiuQing")
const a =1
// 类似vue 中的computed 计算属性
// 用于缓存变量
const studyRun = React.useMemo(() => name + 'String', [name])
const changeName = () => {
setName("mynameiszjq" + Math.random())
}
const giveSonFun = useCallback(() => {
console.log("子组件执行了函数")
}, [a])
// const giveSonFun = () => {
// console.log("子组件执行了函数")
// }
return (
<React.Fragment>
<p>studyRun:{
studyRun}</p>
<button onClick={
changeName}>点击更改studyRun</button>
<div style={
{
border: "2px solid #ccc", height: "300px", width: "500px" }}>
我是A组件
<A giveSonFun={
giveSonFun} />
</div>
</React.Fragment>
);
}
const A = memo(function A(props) {
let {
giveSonFun } = props
console.log(giveSonFun, 'giveSonFun')
return (
<>
我是A组件内容
<hr />
<button onClick={
giveSonFun}>点击我执行父组件传入的方法</button>
</>
)
})
export default App;
同样的页面初始话的时候,A组件渲染了一次:
但是后面我们点击APP函数中的按钮,打印台并没有重新打印函数体;
后面的随机数变化表示我们最少点击了一次,控制台还是没有打印函数体。
所以我们使用useCallback实现了缓存函数的效果。
我们不难发现,useCallback有两个参数:
第一个参数是一个函数体;
第二个参数是一个数组;
其实第二个参数和useEffect的效果一样;
当我们不传入第二个参数的时候,所有的状态改变都会触发useCallback重新返回一个新的缓存函数;
当我们你传入一个空数组的时候,所有状态的改变都不会触发useCallback重新返回一个新的缓存函数;
当我们传入一个数组,并且数组中有变量的时候,只有这个变量状态改变才会触发useCallback重新返回一个新的缓存函数;
我们上边的例子使用了一个变量a作为useCallback返回新缓存函数的条件,事实上我们的a一直没有变;
当我们将a换成 name后,这个缓存函数会根据name变量改变与否来返回新缓存函数与否;
import './App.css';
import React, {
useState, useMemo, useCallback, memo } from 'react'
function App() {
const [name, setName] = useState("LiuQing")
// 类似vue 中的computed 计算属性
// 用于缓存变量
const studyRun = React.useMemo(() => name + 'String', [name])
const changeName = () => {
setName("mynameiszjq" + Math.random())
}
const giveSonFun = useCallback(() => {
console.log("子组件执行了函数")
}, [name])
return (
<React.Fragment>
<p>studyRun:{
studyRun}</p>
<button onClick={
changeName}>点击更改studyRun</button>
<div style={
{
border: "2px solid #ccc", height: "300px", width: "500px" }}>
我是A组件
<A giveSonFun={
giveSonFun} />
</div>
</React.Fragment>
);
}
const A = memo(function A(props) {
let {
giveSonFun } = props
console.log(giveSonFun, 'giveSonFun')
return (
<>
我是A组件内容
<hr />
<button onClick={
giveSonFun}>点击我执行父组件传入的方法</button>
</>
)
})
export default App;
每点击一次name的值都会被重新set,所有每次传入子组件都是一个新的giveSonFun 函数,所有A组件会从新渲染。
总结:
memo:为了像纯组件一样,根据变量前后状态来判断更新组件与否;
useMemo:缓存变量;
useCallback:缓存函数;
附参考地址:https://blog.csdn.net/leelxp/article/details/107822103