乐趣区

关于前端:React-Hook解析

写在后面的话

依据 React 官网文档介绍,Hook 是 React 16.8 的新增个性,它能够让你在不编写 class 的状况下应用 state 以及其余的 React 个性。

那么在有 class 组件的状况下,咱们为什么还要用 Hook 呢?在什么状况下应该用 Hook 组件呢?

React 组件

React 能够通过 class 和 function 两种形式创立组件。

class 组件


class 组件实例化要通过几个过程:

  • 初始化组件
  • 执行构造函数
  • 继承父类属性
  • 绑定事件
  • 初始化 state

这样做会带来肯定负作用:

  • 大量组件实例化过程会占用内存,对性能造成肯定影响
  • 如果在构造函数里通过 bind 绑定事件,代码可读性较差;而用箭头函数申明事件处理函数又容易造成子组件的反复渲染

函数组件


函数组件相当于申明了一个能够返回 UI 的函数,这样做的益处是没有了实例化过程,不会对内存造成累赘。相应的,因为没有实例化,函数组件也就没有本人的 this,没有本身的 state,更不能拜访生命周期钩子函数。函数组件又被成为无状态组件。

函数组件渲染须要的数据来自父组件传递的 props

什么时候用函数式申明组件?

理论我的项目开发中的组件个别不会是简略的一层构造,通常是父组件嵌套几个子组件。咱们能够把须要用到生命周期解决逻辑、须要保护本身状态的父组件用 class 申明,简略的只须要接管父组件 props 的子组件用 function 申明。

React Hook

随着“函数式编程”思维的深刻,React 开发了用于函数组件中挂钩状态和生命周期的 Hook。有了 Hook,组件中的状态不再是聚合成一个对象,而是离开独立治理;而且不再须要在开发时在意生命周期的应用,这给了开发者很大的自在。

Hook 是一个非凡的函数,它能够让你“钩入”React 的个性。例如,useState 是容许你在 React 函数组件中增加 state 的 Hook.

useState


上图中通过函数式申明了一个叫 Counter 的组件,并调用 useState 给组件申明了一个 count 的 state。

调用 useState 时做了什么?
它定义一个“state 变量”。这里的变量叫 count,然而咱们能够叫他任何名字,比方 banana。这是一种在函数调用时保留变量的形式 —— useState 是一种新办法,它与 class 外面的 this.state 提供的性能完全相同。一般来说,在函数退出后变量就会”隐没”,而 state 中的变量会被 React 保留。

useState 须要哪些参数?
useState() 办法外面惟一的参数就是初始 state。不同于 class 的是,咱们能够依照须要应用数字或字符串对其进行赋值,而不肯定是对象。在示例中,只需应用数字来记录用户点击次数,所以传了 0 作为变量的初始 state。(如果咱们想要在 state 中存储两个不同的变量,只需调用 useState() 两次即可。)

useState 返回什么?
返回值为:以后 state 以及更新 state 的函数。这就是咱们写 const [count, setCount] = useState() 的起因。这与 class 外面 this.state.countthis.setState 相似,惟一区别就是你须要成对的获取它们。

通过以上操作,咱们能够在 UI 中拿到 count 作为渲染数据,出现在视图上

useEffect

在下面的实例中,如果咱们想每点击一次按钮控制台就打印一次信息,应该怎么做呢

Effect Hook 能够让你在函数组件中执行副作用操作。

useEffect 做了什么?
通过应用这个 Hook,你能够通知 React 组件须要在渲染后执行某些操作。React 会保留你传递的函数(咱们将它称之为“effect”),并且在执行 DOM 更新之后调用它。

为什么在组件外部调用 useEffect?
useEffect 放在组件外部让咱们能够在 effect 中间接拜访 count state 变量(或其余 props)。咱们不须要非凡的 API 来读取它 —— 它曾经保留在函数作用域中。Hook 应用了 JavaScript 的闭包机制,而不必在 JavaScript 曾经提供了解决方案的状况下,还引入特定的 React API。

useEffect 会在每次渲染后执行吗?
是的,默认状况下,它在第一次渲染之后_和_每次更新之后都会执行。你可能会更容易接受 effect 产生在“渲染之后”这种概念,不必再去思考“挂载”还是“更新”。React 保障了每次运行 effect 的同时,DOM 都曾经更新结束。

能够说 useEffect 能够代替 class 组件中的 componentDidMount、componentDidUpdate、componentWillUnmount 生命周期,每次组件渲染完后组件都会执行 useEffect 的操作。

为什么 useEffect 能拿到每次更新的值?
组件每次渲染后都会生成新的 effect,笼罩之前的值,这时拿到的 count 也是最新的

useEffect 传递的参数
useEffect 中传递的第一个参数是一个函数,示意组件渲染后要执行的操作。咱们还能够在组件中传第二个参数——这个参数示意 useEffect 执行的依赖,也就是说,只有这个参数发生变化时 useEffect 才会执行,这就实现了 useEffect 的优化

如果你要应用此优化形式,请确保数组中蕴含了 所有内部作用域中会随工夫变动并且在 effect 中应用的变量,否则你的代码会援用到先前渲染中的旧变量。

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),能够传递一个空数组([])作为第二个参数。这就通知 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不须要反复执行。这并不属于非凡状况 —— 它仍然遵循依赖数组的工作形式。

React 会在渲染实现后提早一段时间执行 useEffect,这使得额定操作很不便。

useEffect 返回值
每个 effect 都能够返回一个革除函数。如此能够将增加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。能够认为返回的函数会在组件卸载时执行,用来清理定时器等工作

React 何时分明 effect?
React 会在组件卸载的时候执行革除操作。正如之前学到的 effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行以后 effect 之前对上一个 effect 进行革除。

为什么用 Hook 组件?

在组件之间复用状态逻辑很难

React 没有提供将可复用性行为“附加”到组件的路径(例如,把组件连贯到 store)。如果你应用过 React 一段时间,你兴许会相熟一些解决此类问题的计划,比方 render props 和 高阶组件。然而这类计划须要从新组织你的组件构造,这可能会很麻烦,使你的代码难以了解。如果你在 React DevTools 中察看过 React 利用,你会发现由 providers,consumers,高阶组件,render props 等其余形象层组成的组件会造成“嵌套天堂”。这阐明了一个更深层次的问题:React 须要为共享状态逻辑提供更好的原生路径。

你能够应用 Hook 从组件中提取状态逻辑,使得这些逻辑能够独自测试并复用。Hook 使你在无需批改组件构造的状况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。

简单组件变得难以了解

咱们常常保护一些组件,组件起初很简略,然而逐步会被状态逻辑和副作用充斥。每个生命周期经常蕴含一些不相干的逻辑。例如,组件经常在 componentDidMountcomponentDidUpdate 中获取数据。然而,同一个 componentDidMount 中可能也蕴含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中革除。互相关联且须要对照批改的代码被进行了拆分,而齐全不相干的代码却在同一个办法中组合在一起。如此很容易产生 bug,并且导致逻辑不统一。

在少数状况下,不可能将组件拆分为更小的粒度,因为状态逻辑无处不在。这也给测试带来了肯定挑战。同时,这也是很多人将 React 与状态治理库联合应用的起因之一。然而,这往往会引入了很多抽象概念,须要你在不同的文件之间来回切换,使得复用变得更加艰难。

为了解决这个问题,Hook 将组件中互相关联的局部拆分成更小的函数(比方设置订阅或申请数据),而并非强制依照生命周期划分。你还能够应用 reducer 来治理组件的外部状态,使其更加可预测。

真正拥抱函数式编程

Hook 使你在非 class 的状况下能够应用更多的 React 个性。 从概念上讲,React 组件始终更像是函数。而 Hook 则拥抱了函数,同时也没有就义 React 的精力准则。Hook 提供了问题的解决方案,无需学习简单的函数式或响应式编程技术。

退出移动版