react的hooks只要包括下面15个:
react16有10个
react18是5个
hooks解决的问题是:
- 为函数组件提供生命周期
- 为函数组件创建状态
- 提取函数组件的重复逻辑
根据作用划分
我们可以根据具体作用对他进行重新划分:处理状态的有8个,处理副作用的有3个,优化组件的有2个,工具hooks有2个。
一:状态hooks
1.1 useState ---v16
函数组件里面,只要props和state发生变化都会触发组件更新,useState是批量更新的,如果同一个状态,修改多次,只有最后一次起作用。
基本使用
1.2 useReducer ---v16
1.必须在一个组件里面使用,不能跨组件。
2.适用于当修改state前需要执行大量重复逻辑的场景。
3.相当于是一个小型的redux
.3 useContext
1.子组件用useContext获取父组件传过来的context,主要的应用场景就是跨级传值。
2.它的弊端:如果在context
里面存储了a,b
两个变量,和setA,setB
的两个方法,把a
和setA
传入A
组件,把b
和setB
传入B
组件,当我用setA
修改a
变量的时候,即便B
组件没有使用 a
变量,但是B
组件也会被重新渲染。解决这个问题的办法就是把a
变量和b
变量拆分到不同的context
里面,这样又会出现大量的context.provide
的嵌套。陷入嵌套地狱!
3.综上所述,context只适用于场景比较简单的嵌套组件里面。关键时刻还得专门的状态管理器上场,比如redux,zustand,jotai。
1.4 useRef
它用来存储dom,也可以用来存储那些不会引发重渲染的值,也就是说如果用ref存储了值,即使这个值发生了改变,他也不会导致组件重渲染。
1.5 useImperativeHandle
如果父组件给子组件传了一个ref
,在子组件里面可以将这个ref
指定给某个元素,这样父组件就能够轻松操控这个子组件里面的元素了。但是如果父组件想要操纵子组件的一些值或者是方法呢?此时就可以用useImperativeHandle
将子组件里面的一些值或者方法暴露出去,供父组件使用,这个hook
常常在组件封装的时候用到。
他接受三个参数,具体是:
具体用法
1.6 useSyncExternalStore
它主要是给redux和mobox这种状态管理器使用的,目的是要组件在concurrent模式下也能安全准确的拿到state。所以这个hook一般在开发的时候也用不到。
1.7 useTransition
启用过度任务,现实使用场景是:输入搜索框,当我们在input里面输入文本,然后在onchange的时候搜索数据的时候,一般会先用state创建一个loading设置loading是true,在页面上要他显示组件,等数据加载好以后就将loading改成false,然后驱动页面更新,显示加载后的数据。
有了useTransition以后,上面的loading就不要了,它会返回2个参数,一个是loading,一个是延迟执行函数。我们只需要将要做的事情加入延迟执行函数,他就能自己驱动loading发生改变。
1.8 useDeferredValue
useDeferredValue 用来包裹延迟的值,作用和useTransion一样,但是用法不同,一个是延迟执行函数,一个是延迟渲染值。
二. 副作用
2.1 useEffect
它里面的代码异步执行。
如上在 useEffect 中做的功能如下:
- ① 请求数据。
- ② 设置定时器,延时器等。
- ③ 操作 dom , 在 React Native 中可以通过 ref 获取元素位置信息等内容。
- ④ 注册事件监听器, 事件绑定,在 React Native 中可以注册 NativeEventEmitter 。
- ⑤ 还可以清除定时器,延时器,解绑事件监听器等。
知识点汇总
1.如果没有依赖值那就每次刷新都执行
2.如果依赖是[],只有页面挂载的时候执行一次
3.如果依赖数组里面有值,那么每次依赖值发生变化的时候才更新
4.它里面有个return出去的函数是组件卸载前要执行的
2.2 useLayoutEffect
它里面的代码同步执行。所以不会出现闪屏
① 首先 useLayoutEffect 是在 DOM 更新之后,浏览器绘制之前,这样可以方便修改 DOM,获取 DOM 信息,这样浏览器只会绘制一次,如果修改 DOM 布局放在 useEffect ,那 useEffect 执行是在浏览器绘制视图之后,接下来又改 DOM ,就可能会导致浏览器再次回流和重绘。而且由于两次绘制,视图上可能会造成闪现突兀的效果。
② useLayoutEffect 的回调函数中代码执行会阻塞浏览器绘制。
如果你使用useEffect去操作state更新页面,发现页面有闪动,你就可以使用useLayoutEffect进行优化,但是useLayoutEffect会阻塞页面更新。因为他是同步执行的。
2.3 useInsertionEffect
它的执行时机是dom更新前,一般我们都不会使用它,具体的使用场景是:为了解决css-in-js在渲染的过程中注入样式,会导致页面重绘问题。所以有了这个hook,我们就可以在dom更新前,把它的样式全部注入进去,就不会出现页面重绘问题了。
总结看看他们的真实的效果
三. 性能优化
3.1 useMemo对比useCallback
useMemo是用来缓存值的hook,useCallback是用来缓存函数的hook。
一般在父组件里面嵌套子组件,如果父组件更新了,子组件就会自动更新。
为了节能,我们想要父组件更新了,如果子组件的props
没有发生变化,他就可以不用更新。
此时你可以用React.memo()
包裹组件。但是如果父组件给子组件传入的是函数或者是一个对象,你会发现在父组件每刷新一次,子组件也会刷新一次,即使函数表面上并没有发生变化。
这是因为当父组件刷新的时候,函数在内存里面的地址发生了变化,导致React.memo()的比较结果是值发生了变化。
如何解决这个问题呢?就需要useMemo
和useCallback
上场了,用他们把值和函数包裹住,保证,父组件刷新了,只要依赖值不变,函数就不会发生变化,传入子组件以后,子组件就不会更新。
四.工具 hooks
4.1 useDebugValue
useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。这个hooks目的就是检查自定义hooks。 你可以理解成他就是一个用来替换console.log帮你调试的hook。
用法:
测试:
4.2 useId
当ReactSSR重构项目以后,启动项目,你会发现当服务端渲染一次以后,由于有些组件的id是用随机数获取到的,导致服务端渲染和浏览器渲染产生的id不同,即使浏览器加载的组件其他地方和服务器加载的组件一样,它依旧会因为id不同而重新渲染。这就会造成性能的消耗。为了解决这个问题,react专门提供了一个hooks,帮助组件不管是服务器渲染,还是浏览器渲染,都只有一个id。
原文链接:https://juejin.cn/post/7407643004490661898