一、背景 ---- 为什么出现Hooks
在使用class定义的组件中,我们可以使用到许多 React特性,例如:state、各种组件生命周期钩子等;
但是在函数定义的组件中,我们却无能为力,因此 React16.8版本推出了 React Hooks,通过它可以更好的在函数定义组件中使用 React特性。
二、React Hooks中的useEffect
钩子
Hooks中useEffect 是如何区分生命周期钩子的
useEffect可以看成是 componentDidMount、componentDidUpdate和 componentwillUnmount三者的结合。
useEffect( callback,[ source])
生命周期函数的调用主要是通过第二个参数[ source]来进行控制有如下几种情况:
-
[ source]参数不传时,则第一次渲染之后和每次更新之后都会执行
useEffect(()=>{ console.log('初始化与每次更新之后,都会执行') })
-
[ source]参数传 [ ] 时,则外部的函数只会在初始化时调用一次,返回的那个函数也只会最终在组件卸时调用一次
useEffect(()=>{ console.log('componentDidMount') return ()=>{ console.log('componentwillUnmount') } },[])
-
[source]参数有值时,则只会监听到数组中的值发生变化后,才优先调用返回的那个函数,再调用外部的函数
useEffect(()=>{ console.log('仅在count值发生变化时执行!') },[count])
三、React Hooks 中的useState
钩子
状态钩子( usestate):用于定义组件的 State,以及实现修改其state的功能
usestate语法说明
- 只接受一个参数:参数是状态的初始值
- 返回的是数组:数组中第一项是状态名,第二项是修改状态的方法
示例:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
四、React Hooks中其它内置钩子
-
useContext
:获取 context -
useReducer
:类似于 Redux思想的实现,但其并不足以替代 Redux可以理解成一个组件內部的redux;并不是持久化存储会随着组件被销毁而销毁。属于组件内部各个组件是相互隔离的,单纯用它并无法共享数据。配合 useContext的全局性可以完成一个轻量级的Redux。 -
useCallback
:缓存回调函数,避免传入的回调每次都是新的函数实例而导致依赖组件重新渲染,具有性能优化的效果 -
useMemo
:用于缓存传入的 props,避免依赖的组件每次都重新渲染 -
useRef
:获取组件的真实节点 -
useLayoutEffect
:DOM更新同步钩子。用法与 useEffect类似只是区别于执行时间点的不同。useEffect属于异步执行,并不会等待DOM真正渲染后执行
useLayoutEffect 则在真正渲染后才触发,可以获取更新后的 state
-
自定义钩子( useXxxxx):基于Hooks,可以引用其它Hooks这个特性我们可以编写自定义钩子
自定义Hooks示例(获取/修改鼠标位置):
调用自定义的Hooks:
五、React hooks 的优势
-
1、方便跨组件复用:其实 HOC的出现,就是为了复用,相比于HOC, Hooks作为官方的底层API,最为轻量,而且改造成本小,不会影响原来的组件层次结构。
-
2、避免HOC嵌套地狱
避免了高阶组件经常使用,导致整个组件树变得臃肿的情况 -
3、class定义的组件,不同的生命周期使逻辑变得分散,且混乱不易维护和管理
-
4、不需要时刻关注this的指向问题
-
5、状态与 UI 隔离:正是由于Hooks的特性,状态逻辑会变成更小的粒度,并且极容易被抽象成—个自定义 Hooks组件中的状态和 UI 变得更为清晰和隔离
六、Hooks 注意:
- 避免在循环/条件判断/嵌套函数中调用hooks,
- 只有函数定义组件中才可以使用hooks,在类组件或者普通函数中不能调用Hooks