发布时间:2024-12-31 10:01
函数式组件中,使用useCallback对函数进行缓存(被外层函数包裹,相当于闭包),组件再次更新时(函数重新执行)会根据依赖是否变化决定选用缓存函数【之前生成的函数】还是新函数【新生成的上下文】。
一般会在嵌套组件中,与函数式组件的memo和类组件的PureComponent一起使用【会对传入props参数逐个进行浅比较决定是否需要更新】,来提高页面性能。
传入箭头函数还是普通函数没有影响
useCallback第二个参数决定组件更新是否生成新函数,函数内部使用到的依赖尽可能在第二个参数写全,否则会有意想不到的问题(序列4)。
何时生成新函数 | 第二个参数 |
---|---|
组件首次执行及更新都会生成新函数 | 空 |
组件首次执行生成,之后不变 | [] |
组件首次执行、依赖变化时生成新函数 | [state, ref.current] 这两类 |
嵌套组件中 memo搭配useCallback和不使用useCallback对子组件更新的影响
(情况1)不使用useCallback时,外层组件每次更新相当于重新生成新函数funcHang,传给子组件。子组件通过memo包裹对传入props参数进行浅比较,发现onClick触发的函数有变化,进而子组件更新。
(情况2)使用useCallback时,第二参数为[]
,外层组件每次更新时(暂时不考虑依赖)都会复用上次函数。子组件接收到传入props的funcHang没有变化,所以子组件不会发生更新。
setxxx更新逻辑:
当setxxx触发更新时,App函数重新执行(相当于新的作用域),当执行到const funcHang = useCallback(...);
useCallback内部会比较之前依赖preDeps
和现在依赖nextDeps
是否相等if (areHookInputsEqual(nextDeps, prevDeps))
;相等true直接返回之前函数,不相等false就返回最新传入的函数。
以下是依赖没写全,导致函数没有及时更新。访问不到最新的数据问题:
(步骤0)代码及初始界面: useCallback函数内部使用了count1和count2,可依赖只有count1:
export function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
// 当count2发生变化时,触发funcHang内部count2是0;除非count1变化引起生成新函数count2才是最新值
const funcHang = useCallback(function() {
console.log("function run:", count1, count2);
}, [count1]);
return (
<div>
<h2>params: { count1 } { count2 }</h2>
<button onClick={ funcHang }>触发</button>
<button onClick={ e => { setCount1(pre => pre + 1);} }>update Count1</button>
<button onClick={ e => { setCount2(pre => pre + 1);} }>update Count2</button>
</div>
)
}
(步骤1)点击按钮update Count1,再触发。打印输出function run: 1 0
(步骤2)点击按钮update Count2,再触发。打印输出function run: 1 0
(步骤3)再次点击按钮update Count1,再触发。打印输出function run: 2 1
分析:
总结:函数使用的是生成时所处App上下文中的数据,注意函数何时会被更新;
业务系统兼容数据库Oracle/PostgreSQL(openGauss)/MySQL的琐事
对象的序列化流ObjectOutputStream和对象的反序列化流ObjectInputStream
linux 内存取证_Linux内存取证lime+volatility(原创2019年10月10日)
除了 Qiankun, 这些微前端框架或许更适合你「建议收藏」
openharmony北向应用开发实例之HelloWorld
Flutter 从 TextField 安全泄漏问题深入探索文本输入流程
vue3【watch检测/监听】watch检测数据变化&&监听使用