Ahooks源码分析之usePersistFn

开发 前端
官方给的demo中更新textRef写在了useEffect中,为什么usePersistFn不这样实现?

usePersistFn

usePersistFn可以持久化function,保证函数地址永远不会变化。

import { useRef } from 'react';

export type noop = (...args: any[]) => any;

function usePersistFn<T extends noop>(fn: T) {
const fnRef = useRef<T>(fn);
// 每次渲染fn的最新值都会记录在fnRef中
fnRef.current = fn;

const persistFn = useRef<T>();
// 初次渲染时给persistFn赋值,此后persistFn不会更新
if (!persistFn.current) {
persistFn.current = function (...args) {
return fnRef.current!.apply(this, args);
} as T;
}

// 返回persistFn,感叹号表示返回值类型非null或undefined,因为初次渲染时persistFn就被赋值为了函数
return persistFn.current!;
}

export default usePersistFn;

为什么要用usePersistFn?

在React官方文档中提到

在某些场景中,你可能会需要用 useCallback 记住一个回调,但由于内部函数必须经常重新创建,记忆效果不是很好,导致子组件重复 render。对于超级复杂的子组件,重新渲染会对性能造成影响。通过 usePersistFn,可以保证函数地址永远不会变化。

官方给出的demo如下

function Form() {
const [text, updateText] = useState('');
const textRef = useRef();

useEffect(() => {
textRef.current = text; // 把它写入 ref
});

const handleSubmit = useCallback(() => {
const currentText = textRef.current; // 从 ref 读取它
alert(currentText);
}, [textRef]); // 不要像 [text] 那样重新创建 handleSubmit

return (
<>
<input value={text} onChange={e => updateText(e.target.value)} />
<ExpensiveTree onSubmit={handleSubmit} />
</>
);
}
复制代码

ExpensiveTree是一个复杂的子组件,其接受一个props handleSubmit函数。如果使用useCallback,由于handleSubmit函数内部使用了text变量,便要写为如下形式:

const handleSubmit = useCallback(() => {
alert(text);
}, [text]);
复制代码

只要text发生变化,useCallback接收的内部函数便要重新创建,导致handleSubmit函数的引用地址发生变化。进而引起子组件ExpensiveTree的重渲染,对性能产生影响。

usePersistFn的目标便是持久化接收的函数,且调用时内部函数引用的变量(上例为text)能获取到实时的值(useCallback的依赖传空数组也能实现持久化函数,但无法获取实时的值)

官方给的demo中更新textRef写在了useEffect中,为什么usePersistFn不这样实现?

如果在子组件的useEffect回调函数中调用usePersistFn就会出现问题。因为渲染时会先执行子组件的useEffect,后执行父组件自定义hooks的useEffect。

文章出自:​​前端餐厅ReTech​​,如有转载本文请联系前端餐厅ReTech今日头条号。

github:​​https://github.com/zuopf769​

责任编辑:武晓燕 来源: 今日头条
相关推荐

2022-08-16 21:01:56

runAsyncreload数据

2022-06-06 08:02:21

ahooks架构hooks

2011-05-26 10:05:48

MongoDB

2021-03-23 09:17:58

SpringMVCHttpServletJavaEE

2024-06-13 07:55:19

2021-07-06 09:29:38

Cobar源码AST

2012-09-20 10:07:29

Nginx源码分析Web服务器

2011-05-26 16:18:51

Mongodb

2020-07-28 08:54:39

内核通信Netlink

2022-07-01 07:31:18

AhooksDOM场景

2009-07-08 13:22:30

JDK源码分析Set

2017-01-12 14:52:03

JVMFinalRefere源码

2022-08-27 08:02:09

SQL函数语法

2022-01-06 07:06:52

KubernetesResourceAPI

2022-05-30 07:36:54

vmstoragevmselect

2012-09-06 10:07:26

jQuery

2021-09-05 07:35:58

lifecycleAndroid组件原理

2019-09-09 06:30:06

Springboot程序员开发

2023-03-17 07:53:20

K8sAPIServerKubernetes

2017-01-11 14:02:32

JVM源码内存
点赞
收藏

51CTO技术栈公众号