为什么要用Hook?

介绍Hooks之前,首先要给大家说一下React的组件创建方式,一种是类组件,一种是纯函数组件,并且React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。也就是说组件的最佳写法应该是函数,而不是类。。
Hook 解决了我们五年来编写和维护成千上万的组件时遇到的各种各样看起来不相关的问题。无论你正在学习 React,或每天使用,或者更愿尝试另一个和 React 有相似组件模型的框架,你都可能对这些问题似曾相识。
但是我们知道,在以往开发中类组件和纯函数组件的区别是很大的,纯函数组件有着类组件不具备的多种特点,简单列举几条

纯函数组件没有状态
纯函数组件没有生命周期
纯函数组件没有this
只能是纯函数

介绍

虽然hook有很多比class方便的更能但是并不建议它来重构项目,因为在react中的class并没有被弃用,因此我们不建议它来重构你原来的class项目.

Hook 是 React 16.8 的新增特性。它是完全可选的,并且100%向后兼容。它可以让你使用函数组件的方式,运用类组件以及 react 其他的一些特性,比如管理状态、生命周期钩子等。从概念上讲,React 组件一直更像是函数。而 Hook 则拥抱了函数,同时也没有牺牲 React 的精神原则。

流程

什么是Hooks?

'Hooks’的单词意思为“钩子”。
React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。而React Hooks 就是我们所说的“钩子”。
那么Hooks要怎么用呢?“你需要写什么功能,就用什么钩子”。对于常见的功能,React为我们提供了一些常用的钩子,当然有特殊需要,我们也可以写自己的钩子。下面是React为我们提供的默认的四种最常用钩子

useState()
userContext()
userReducer()
useEffect()

本质上的运作规则

Hook 将组件中相互关联的部分拆分成更小的函数,也就是搭积木,由更小的积木来搭建这个项目,它的灵活性很大,可以自由发挥

class的缺点和用hook的理由

除了代码复用和代码管理会遇到困难外,我们还发现 class 是学习 React 的一大屏障。你必须去理解 JavaScript 中 this 的工作方式,这与其他语言存在巨大差异。还不能忘记绑定事件处理器。没有稳定的语法提案,这些代码非常冗余。大家可以很好地理解 props,state 和自顶向下的数据流,但对 class 却一筹莫展。即便在有经验的 React 开发者之间,对于函数组件与 class 组件的差异也存在分歧,甚至还要区分两种组件的使用场景。

hook的优点:

  1. 代码可读性更强,原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者不利于维护和迭代,通过 React Hooks
    可以将功能代码聚合,方便阅读维护。例如,每个生命周期中常常会包含一些不相关的逻辑。一般我们都会在 componentDidMount 和
    componentDidUpdate 中获取数据。但是,同一个 componentDidMount
    中可能也包含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount
    中清除。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。如此很容易产生
    bug,并且导致逻辑不一致。
  2. 组件树层级变浅。在原本的代码中,我们经常使用 HOC/render props
    等方式来复用组件的状态,增强功能等,无疑增加了组件树层数及渲染,在 React DevTools 中观察过 React 应用,你会发现由
    providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。而在 React
    Hooks 中,这些功能都可以通过强大的自定义的 Hooks 来实现。
  3. 不用再去考虑 this 的指向问题。在类组件中,你必须去理解 JavaScript 中 this 的工作方式

hook的缺点:

对一些钩子函数不支持。当下 v16.8 的版本中,还无法实现 getSnapshotBeforeUpdate 和 componentDidCatch 这两个在类组件中的生命周期函数。

Hook 规则

不在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。
不在普通的 JavaScript 函数中调用 Hook,在 React 的函数组件或者自定义 Hook 中调用 Hook。

Hook API

名称 描述
useState 在函数组件中维护自己的状态
useEffect 在函数组件中实现生命周期钩子函数
useContext 用来处理多层级传递数据的方式,减少组件嵌套
useReducer 跟react-redux的使用方式一样,算是提供一个 mini 的 Redux 版本
useCallback 获得一个记忆函数,避免在某些情况下重新渲染子组件,用来做性能优化
useMemo 获得一个记忆组件,和useCallback非常类似,它适用于返回确定的值
useRef 生成对 DOM 对象的引用,它是一个真正的引用,而不是把值拷过去
useImperativeHandle 透传ref,用于让父组件获取子组件内的引用
useLayoutEffect 同步执行副作用,在页面完全渲染完成后,操作DOM

useState
在类组件中,我们使用 this.state来保存组件状态,并对其修改触发组件重新渲染。而在函数组件中,由于没有 this 这个黑魔法,可能通过 useState 来帮我们保存组件的状态。

import React, { useState } from "react";

export default function Button() {
  const [buttonText, setButtonText] = useState("Click me, please");

  function handleClick() {
    return setButtonText("Thanks, been clicked!");
  }

  return <button onClick={handleClick}>{buttonText}</button>;
}

useState(),返回一个 state,以及更新 state 的函数。
useState() 中第一个参数是值或者对象,初始渲染期间,返回的状态 (state) 是传入的第一个参数相同。
如果依赖于先前的state,在第二个参数中接收先前的 state,并返回一个更新后的值。
注意:与类组件中的 setState 方法不同,useState 不会自动合并更新对象。当第一个参数是一个对象时,你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。

useEffect
语法:useEffect(fn,Array)

第一个参数传递函数,可以用来做一些副作用比如异步请求,修改外部参数等行为。
第二个参数是个数组,数组中的值发生变化才会触发 useEffect 第一个参数中的函数。
如果第二个参数是个空数组的话,默认会在页面加载后执行一次。
如果第一个参数有返回值,会在组件销毁或者调用函数前调用。
可以使用useEffect模拟componentDidMount、 componentDidMount 和 componentWillUnmount钩子函数。

useContext
用来处理多层级传递数据的方式,使用 useContext 可以解决 Consumer 多状态嵌套的问题

useReducer
useReducer 这个 Hooks 在使用上几乎跟 React-Redux 一模一样,唯一缺少的就是无法使用 redux 提供的中间件,算是提供一个 mini 的 Redux 版本。

useCallback
通过 useCallback 获得一个记忆后的函数,避免函数组件在每次渲染的时候如果有传递函数的话,重新渲染子组件。用来做性能优化。

useMemo
记忆组件,和useCallback类似,不同的是:useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并且将函数执行结果返回给你。所以在前面的例子中,可以返回 handleClick 来达到存储函数的目的。

所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数计算得到一个确定的值,比如记忆组件。

useRef
跟 createRef 类似,都可以用来生成对 DOM 对象的引用。不同点在于,它是一个真正的引用,而不是把值拷过去。

useImperativeHandle
透传ref,用于让父组件获取子组件内的引用。

useLayoutEffect
大部分情况下,使用 useEffect 就可以帮我们处理组件的副作用,但是如果想要同步调用一些副作用,比如对 DOM 的操作,就需要使用 useLayoutEffect,useLayoutEffect 中的副作用会在 DOM 更新之后同步执行。

在上面的例子中,useLayoutEffect 会在 render,DOM 更新之后同步触发函数,会优于 useEffect 异步触发函数。

自定义Hook
demo

总结:

Hook是
完全可选的。 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook。
100% 向后兼容的。 Hook 不包含任何破坏性改动。
现在可用。 Hook 已发布于 v16.8.0。
没有计划从 React 中移除 class。
Hook 不会影响你对 React 概念的理解。 恰恰相反,Hook 为已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。

今天就到这里了,喜欢的话可以三连哦