简单介绍一下
hook是React 16.8新增的特性,在此之前使用state特性都是需要编写class的。也就是说在16.8之后函数组件中也是可以维护状态等特性的。hook是可选的,也就是说对已经存在的react组件,或者是以后没有开发的组件你都可以选择用或者不用。习惯使用class的大佬也是可以继续使用的,官方给出来明确的说法,会继续为class提供支持的。不过理论上来说它可以成为类组件的替代品,还是很强的。
常用的几个hook
useState
它是一个在函数组件中使用的函数,用于在函数组件中可以维护状态。
-
useState函数需要一个参数,这个参数的值表示这个状态的初始值。类型不限,如果状态的初始值需要通过一系列计算之后才能得到的话,也可以传入一个函数作为参数,传函数的时候切记要返回值,否则就抓瞎了
-
useState函数会返回一个数组,该数组包含两项,第一个是状态的初始值,第二个是改变状态的函数(类组件中是this.setState())。
-
一个函数组件中可以有很多个状态,类组件只有一个state。hook这么做的好处是帮助开发者很好的横切关注点(当然了,也可以类似于类组件中只写一个state,把所有的状态都扔进去,在函数组件中各种状态混杂是没有意义的)
useEffect
在函数组件中用来处理副作用的hook,类似于类组件中componentDidMount(只是类似,有区别的)。 可以处理的副作用例如:
- 异步操作(网络请求,计时器。。)
- 更改真实的DOM(基本不推荐直接操作真实DOM)
useEffect函数接受一个函数作为参数,接受的函数就是需要进行副作用操作的函数,清理函数是没有返回值的(因为是在组件销毁的时候执行,再返回也没有作用了)
传参数需要注意的是:
- 有时候有些副作用是需要清除的,此时参数函数可以返回一个清理函数,用于清理副作用。
- 第一点的时候说了,可以返回一个清理函数。代表着你传入的参数函数可以有返回值,问题就在这里,它只接收清理函数。所以在网络请求的时候,不要写
effect(async()=>…)这种代码(了解ES7新增的这两关键字的大佬会知道,使用async修饰了函数,无论如何都是会返回一个promise的)。可以这样写useEffect(() => { 异步函数fetch(){ //你可以在这里等 await ···· } fetch() })
effect hook的一些小芝士😊:
- 这个函数的运行时间点是在页面完成真实ui渲染之后(LayoutEffect Hook就是在完成了dom改动,但是没有呈现出来的时候运行,所以它是会阻塞浏览器的js线程的, 所以尽量使用effect hook),它自己就是异步的,不会阻塞的
- effect hook可以看成是componentDidMount componentDidUpdate componentWillUnmount生命周期的组合
- 与componentDidMount的区别,effect是用户看到了UI渲染之后执行,是异步的。componentDidMount是同步的,用户没有看到UI更新就执行
- effec接受第二个参数
- 是一个数组,该数组记录当前副作用函数中依赖的数据
- 不传的时候,在组件第一次渲染和以后的每一次重新渲染都是会执行的,传空数组,组件第一次渲染的时候执行。传依赖数据,每次重新渲染,如果依赖数据跟上一次不一样,就会执行副作用函数
useCallBack useMemo
callback用于固定函数,即得到一个引用地址不轻易变化的函数。 memo用于得到一个固定引用的值,通常用于保持一些比较稳定的数据。类似于VUE中的计算属性
两个参数:
- 第一个是函数,callback会固定该函数的引用地址,memo则是执行函数,返回固定引用的值
- 第二个是数组,记录依赖项的,三种情况请看effect
个人总结:(纯供讨论,勿喷)
- useCallback和useMemo一般情况下我都是使用在角色是父组件且需要频繁重新渲染的的函数组件中。用来固定传给子组件的一些属性。当父组件中的某一处改变之后,按理来说子组件是没必要重新渲染的,因为跟子组件没关系,但是子组件其实也是更新了,这样的话,如果属性较多或者渲染较频繁,或多或少的会影响到性能。至于纯子组件(内部没有引入其他组件),我一般不用,毕竟hook对于一些人来说还是比较新的。在公司写的代码不可能是你一个人一直在管,所以有时候有些人可能不太明白,不利于维护,其次也不易阅读,对于子组件重新渲染,函数或者变量重新生成在整个程序进程中占用的内存是微不足道的,不用也行,可以在用react.memo()包裹一下组件。所以视情况而定,凡事有好就有坏的嘛。
useRef
useRef函数,参数可有可无,代表的ref的默认值,返回一个固定的对象{current:···},这个current就是你给挂载的那个元素的真实DOM,一般在需要获取到真实dom的时候使用。
hook相关(以useState为例)
原理:
当调用useState的时候,会有次数标记(n),它会检查该节点对应的状态数组中是否存在下标n,如果不存在,会使用传入的默认值创建一个状态,将该状态加入到状态数组中,下标为n(n=0, 1....),如果存在则忽略默认值,直接得到该状态的值即可。
需要注意的:
-
最好写在函数的起始位置,便于阅读和了解组件的状态情况
-
返回的数组第二项,即改变状态的函数引用是不变的
-
组件重新渲染,只能通过改变状态或者props(同时调用多个状态的改变函数,内部会合并更改),状态更改与否使用的是Object.is比较的
-
更改状态的时候,与类组件不同的是,它不是将传入的值和原来的值进行合并,而是直接替换,如果是状态是引用数据类型,需要注意,避免丢失部分数据。
-
类组件中想要在状态更改之后使用最新状态或者设置某个组件的值,可以传入第二个参数,可以在状态更新完成之后执行。但是useState不行,而且因为它是异步的,所以不能第一时间拿到最新的状态值。想要在状态更新之后第一时间用到,那么函数组件中可以搭配useEffect来监听该状态。
写在最后
毕竟经验,知识储备都不足,肯定是漏洞百出~~~ 有幸被大佬刷到的话,多多指正,多多讨论