Hooks 详解
Hooks
React Hook/Hooks
- Hook 是 React 16.8 版本后新增的特性/新语法
- 可以让函数式组件使用 state 以及其他 React 特性
注意点
不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。
因为 react 是通过 hook 调用顺序(index) 来判断得。条件判断和循环会打乱原有顺序,产生 bug
State Hook
- 解构赋值一个数组,第一个参数是状态,第二个参数是更新状态的方法,useState 的参数是该状态的初始值:普通类型,对象以及 class
- 状态更新的两种方式,推荐第二种,但 state 为对象,更常用第一种。
但是在 setInterval 中使用 setState,由于setInterval的闭包特性,每次组件render setInterval回调中的state被闭包了导致不会改变,所以此种情况用回调的更新方式可以解决这个问题``或使用 useRef
。**所以应该减少在闭包中使用外部普通变量,尤其是 state。**
- 函数组件中不使用 this,直接调用 state 或方法即可。
注意: class 组件中 this.setState 更新是 state 是合并, setState 中只用传需更新有变化的 state, 而useState 中 setState 是替换,也就是说 useState 中必须传递整个 state
所以这样写:<font style="color:#23263B;"> {...未更新state, 更新的state = value}</font>
需要另外注意的是:不少函数指令式的组件 比如 antd 的 <font style="color:#23263B;">Modal.</font>confirm()
中不应该使用组件内的 state, 因为 state 如何更新 render, 调用 <font style="color:#23263B;">Modal.</font>confirm
的函数也只会执行一次,所以无法引起 modal 内部更新刷新。如果想往 modal 中注入 state 只有使用 <font style="color:#23263B;"><Modal/> 组件</font>
Effect Hook
Effect Hook 可以让你在函数组件中执行副作用操作(就是模拟类式组件中的生命周期钩子)
useEffect Hook 就相当于以下三种钩子的组合:
componentDidMount()、componentDidUpdate()、componentWillUnmount()
- React 中的副作用操作多有:
- 发送 ajax 请求
- 设置订阅/启动定时器
- 手动更改真实 DOM
语法:
effect 在每次渲染的时候都会执行。并且 React** 会**在执行当前 effect 之前对上一个 effect 进行清除。
在需要清除副作用的业务场景中(定时器,异步订阅等)。class 组件要做到这一点需要在 componentDidUpdate 中,手动对更新前的副作用进行清除,然后再订阅新的内容。显然 useEffect 就不用这么麻烦了。
- useEffect 有两个参数,第一个参数是一个函数,可以在里面写副作用操作,并可在函数的 return 函数里进行一些清除操作(清除定时器/异步订阅等),该清除函数会在执行当前 effect 之前,对前一个 effect 进行清除。
- 不写**useEffect 的**第二参数: 第一次渲染之后和每次更新之后都会执行,也就是不管状态更新还是初始化,都会执行 useEffect 中的代码。
- useEffect 第二参数为一个数组。且数组为空,相当于componentDidMount。其 return 函数就有componentWillUnmount__的效果。
- 第二个参数中,写上依赖的变量,即可有 componentDidMount()、和对应状态的 componentDidUpdate() 、等两个钩子的效果。_并且需要注意 处理清除事务的 return 函数,只有在第二个参数为空数组时才算挂载前钩子_
- useEffect 也是一个性能优化的案例,第二个参数,所依赖的值,只有在发生变化时。才会执行 Effect 回调。
**Tip: **
- React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect,因此会使得额外操作很方便。就是说useEffect 是在 DOM 更新后执行的,所以能拿到,最新的 state;
- useEffect** **与其他存在依赖值的 hook, 比如 useMemo、useCallback。依赖参数的规则一致;
- 可使用多个 useEffect,关注分离的处理不同事务逻辑,react 会按顺序依次执行。
Ref Hook
useRef
const params = useRef(初始值)
TS 中 向组件上注入 ref 时需声明 绑定 ref 组件的泛型,就是你 ref 的类型。获取 dom 节点使用 HTMLElement 类型,单纯使用 useRef 存储变量时不用。
useRef<types>(initVal)
在页面整个生命周期中,除了挂载时,ref 会用于页面渲染,之后任何变化都不会引起页面的渲染。
一、useRef 的应用场景:
1.函数组件访问 dom 元素。
2.函数组件整个生命周期里存储变量。
二、useRef 特性:
1.current 中保存的属性 类似 class 组件中的实例属性, 就像一个组件内的全局变量一样.
2.ref.current 发生变化并不会造成 re-render; 会在组件整生命周期里保存。
3.不用于组件渲染的属性,都应该存到 useRef 中。
4.单纯维护变量在 useRef 中,就不必绑定在 dom 节点上了。
5.不应该在 render 阶段更新 current 属性,ref.current 的变化,不应该导致页面更新等副作用
6.不使用 setState 更新 state,直接赋值,能到达和 useRef 一样的效果<不推荐>
三、useRe 当作普遍 ref 使用:
–创建
–标记
–使用
四、不同
类组件的 creatRef 会重复渲染。而 useRef 不会
useCallback 与 useMemo
性能优化与缓存数据。(类似计算属性,class 组件中 使用 get 关键字命名方法也算计算属性)
> useMemo 和 useCallback 的共同点:
- 接收的参数都是一样的,第一个是回调函数,第二个是依赖的数据
- 它们都是当依赖的数据发生变化时才会重新计算结果,起到了缓存作用
> useMemo 和 useCallback 的区别:
- useMemo 计算结果是 return 回来的值,通常用于缓存计算结果的值
- useCallback 计算结果是一个函数,通常用于缓存函数
- 常使用 useCallback(() => callback(), [])缓存匿名函数,(为了避免匿名函数被重复调用的性能问题,暂未知)
> 可以把 useMemo 替换成 useCallback,使用 useCallback 就不用写 return 函数了
1 |
|
注意:
- 如果你的 value 是个函数,那么你就要写成useMemo(()=>(x)=> console.log(x))
- 这是一个返回函数的函数,比较复杂;就使用useCallback
useMemo 和 React.memo
memo 是防止 props 没变时的重新渲染,useMemo 和 useCallback 是防止 props 的不必要变化。
hook 中的性能优化主要有 useMemo 和 React.memo。其中 React.memo 在没有第二的参数的时候相当于 class 中的 PureComponent,当增加了第二个参数的时候相当于声明周期中的 shouldComponentUpdate,但是可以明显感觉到 hook 的使用要更加的简单和灵活。
useMemo 则是 hook 对比 class 一个显著的优势,因为通过 useMemo 我们可以进行更加细粒度的性能优化,这是 class 难以实现的。
自定义 hook
- 本质就是抽离逻辑和状态更新。公司里写得 .store.ts 文件,就是自定义 hook.
- 且约定 使用 use 开头。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!