react教程,如何使用useCallback函数来缓存函数逻辑变量?
发布于 作者:苏南大叔 来源:程序如此灵动~继续聊react
项目中函数式组件的useXxx
系列,本文聊另外一个缓存函数而不是缓存函数结果的useCallback
。和useMemo
对比的话,useMemo
是缓存的函数运算结果,而useCallback
是缓存的函数逻辑中涉及的变量的值+逻辑。监控条件符合(变量变化)的时候,就会从新获取函数中变量取值。
大家好,这里是苏南大叔的程序如此灵动博客,这里记录苏南大叔和计算机代码的故事。本文描述useCallback
的使用方法。本文的主要需求是对list
列表进行维护,通过useCallback
的不同包装,具有不同的运行结果。测试环境:create-react-app@5.0.1
,react@18.2.0
,react-dom@18.2.0
,node@16.14.2
。
案例一,不使用useCallback
不使用useCallback
,先使用普通的函数addItem
。
import React, { useState, useEffect, useCallback } from 'react';
function List() {
let [list, setList] = useState([]);
const addItem = () => {
console.log(list);
list.push('sunan大叔 ' + Date.now().toString().slice(-6));
setList([...list]);
};
useEffect(() => {
setList(['苏南大叔', 'sunan大叔']);
}, []);
return (
<>
{
list.map((item, index) => {
return (
<div key={index}>
{item}
</div>
)
})
}
<button onClick={addItem.bind()}>不使用useCallback</button>
</>
)
}
export default List;
案例二,使用useCallback
,没有监控点
import React, { useState, memo, useEffect, useCallback } from 'react';
function List() {
let [list2, setList2] = useState([]);
const addItem2 = useCallback(() => {
console.log(list2); // []
list2.push('苏南大叔 ' + Date.now().toString().slice(-6));
setList2([...list2]);
}, []);
useEffect(() => {
setList2(['苏南大叔', 'sunan大叔']);
}, []);
return (
<>
{
list2.map((item, index) => {
return (
<div key={index}>
{item}
</div>
)
})
}
<button onClick={addItem2.bind()}>useCallback被缓存但没监控</button>
</>
)
}
export default List
在这个例子中,虽然使用了useCallback()
,但是没有添加监控点。所以,useCallback()
的函数,虽然被缓存了,但是内部的变量并没有取到正确的值,list
取到的值是state
初始值[]
,在useEffect
的初始化动作,显然发生在了useCallback()
之后。所以,在界面上点击按钮的时候,原始的值会被覆盖。
案例三,使用useCallback,并添加监控开关
import React, { useState, memo, useEffect, useCallback } from 'react';
function List() {
let [list3, setList3] = useState([]);
let [list3Plus, setlist3Plus] = useState(false);
const addItem3 = useCallback(() => {
console.log(list3); // 符合监控条件的时候,会刷新这里面的所有变量取值
list3.push('苏南大叔 ' + Date.now().toString().slice(-6));
setList3([...list3]);
}, [list3Plus]);
const addItem3Plus = function () {
setlist3Plus(!list3Plus);
}
useEffect(() => {
setList3(['苏南大叔', 'sunan大叔']);
}, []);
return (
<>
{
list3.map((item, index) => {
return (
<div key={index}>
{item}
</div>
)
})
}
<button onClick={addItem3.bind()}>useCallback默认没开启监控</button>
<button onClick={addItem3Plus.bind()}>开启监控{list3Plus.toString()}</button>
</>
)
}
export default List
这个例子中,使用了useCallback()
,并且添加了监控值list3Plus
。默认情况下,因为监控值list3Plus
没有发生变化,所以,函数内部拿到的list
状态值,仍然是[]
(参考上一条)。通过第二个附加按钮修改了list3Plus
之后,useCallback()
被刷新,得到了最新的list
值,然后再继续添加维护这个list
值。
安装四,使用useCallback,并添加合适的监控点
import React, { useState, memo, useEffect, useCallback } from 'react';
function List() {
let [list3, setList3] = useState([]);
const addItem3 = useCallback(() => {
console.log(list3); // 符合监控条件的时候,会刷新这里面的所有变量取值
list3.push('苏南大叔 ' + Date.now().toString().slice(-6));
setList3([...list3]);
}, [list3]);
useEffect(() => {
setList3(['苏南大叔', 'sunan大叔']);
}, []);
return (
<>
{
list3.map((item, index) => {
return (
<div key={index}>
{item}
</div>
)
})
}
<button onClick={addItem3.bind()}>useCallback开启合适监控点</button>
</>
)
}
export default List
这里,添加了更加合适的监控点list3
,不过,这样的话,实际上这个useCallback
的缓存意义在哪里呢?不解释。
案例四【推荐】
import React, { useState, useCallback } from 'react';
const SunanMemo = () => {
const [count, setCount] = useState(0)
const [flag, setFlag] = useState(true)
const increase = useCallback(() => {
setCount(count + 1)
}, [count])
return (
<div>
<div>
<div>【count: {count}】count不变,useCallback就不变</div><br />
<TestButton title="普通点击" onClick={() => setCount(count + 1)} />
<TestButton title="Callback+bind" onClick={increase.bind()} />
<TestButton title="Callback" onClick={increase} />
</div>
<button onClick={() => setFlag(!flag)}>更新非count的状态,useCallback组件不更新</button>
</div>
)
}
const TestButton = React.memo((props) => {
console.log("props变化,组件就会更新:" + props.title)
return <button onClick={props.onClick}>{props.title}</button>
})
export default SunanMemo;
useCallback
实际上真正的用法是与memo
联合使用的,用于缓存传入memo
组件中的函数(作为props
传入)。memo
过的组件当props
发生变化的时候,才会更新。而把函数作为props
传入的时候,总是会引起子组件的更新。这个时候,就需要useCallback
出场了。函数只有依赖项更新的时候,才会变化。不变化的话,子组件的props
就不会更新,子组件就不会更新。达到节约性能的目的。
然而,这里的useCallback
的函数,使用.bind()
的话,就会破坏这个useCallback
效果。比如上文中的第二个子组件按钮和第三个。一个.bind()
就破坏了全局。
相关文章:
相关链接
- https://newsn.net/say/react-useref.html
- https://newsn.net/say/react-usestate.html
- https://newsn.net/say/react-usememo.html
- https://newsn.net/say/react-useeffect.html
结束语
更多react
相关经验文章,请点击苏南大叔的博客文章:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。