React将引入Hooks,使用有什么好处?

2018-10-3010:00:17WEB前端开发Comments15,400 views1字数 5586阅读模式

2018 ReactConf 大会上,React 官方宣布 React v16.7.0-alpha 将引入 Hooks,乍一看,你可能在想 Hooks 是什么?有什么用?且看下文分析。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

Hooks 是什么?

Hooks 是一种函数,该函数允许你“勾住(hook into)”React 状态和来自函数组件的生命周期功能。Hook 在类内部不起作用,它们允许你无需类就使用 React。(不建议你马上开始重写你现有的组件,但你可以在新组件中开始使用 Hook。)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

React 提供了一些内置 Hook,如 useState,你也可以创建自定义 Hooks 以在不同的组件中复用有状态行为。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

根据 React 官方给出的文档,Hooks 主要分为以下几种:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

  • State Hooks
  • Effect Hooks
  • 自定义 Hooks
State Hook

该示例显示了一个计数器,点击该按钮,值会递增。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

在这里,useState 是一个 Hook,我们在函数组件中调用它以给它添加一些本地状态。React 将在重新渲染之间保留这个状态。useState 返回一对值:currentstate 值和允许你更新它的函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

可以从事件处理程序或其他位置调用该函数,这与类中的 this.setState 类似,除了其不会把旧的和新的状态合并在一起。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

声明多个状态变量文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

可以在单个组件中多次使用 State Hook:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

数组解构语法允许我们给状态变量取不同的名字,这些变量是我们通过调用 useState 声明的,这不是 useState API 的一部分。相反,React 假设如果多次调用 useState,那么在每次渲染的时候要遵循相同的顺序来做。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

Effect Hook

你之前很可能已经执行了数据提取、订阅、或手工改变来自 React 组件的 DOM。我们称这些操作为“副作用(side effect)”,因为它们会影响其他组件,并且在渲染过程中无法完成。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

Effect Hook、useEffect,增加了从函数组件执行副作用的功能。它与 React 类中的 componentDidMount、componentDidUpdate、和 componentWillUnmount 有相同的功能,但是统一为单个 API。(我们将展示一个例子,该示例在 Using the Effect Hook 中对 useEffect 和这些方法进行比较。)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

例如,此组件在 React 更新 DOM 后设置文档标题:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

import { useState, useEffect } from 'react';


function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });


  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

当你调用 useEffect 时,你通知 React 在刷新对 DOM 的更改后运行你的“effect”函数。Effect 在组件内声明,因此可以访问其 props 和 state。默认情况下,React 在每次渲染后运行 effect,包括第一次渲染。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

效果还可以通过返回一个函数来指定它们之后如何“清理”。例如,此组件使用 effect 来订阅朋友的在线状态,并通过取消订阅来清理:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });


  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

在此示例中,当组件卸载时,以及在由于后续渲染而重新运行 effect 之前,React 将取消订阅我们的 ChatAPI。(如果我们传递给 ChatAPI 的 props.friend.id 没有变化,有办法让 React 跳过重新订阅。)就像使用 useState 一样,可以在组件中使用多个 effect:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...

Hook 允许你通过部件的关联情况(例如添加和删除订阅)来组织组件中的副作用,而不是基于生命周期方法强制拆分。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

自定义 Hooks

自定义 Hooks 主要用来复用组件逻辑,详情请阅读:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

https://reactjs.org/docs/hooks-overview.html文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

Hook 的规则

Hook 是 JavaScript 函数,但强加了两个额外的规则:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

  • 只能在顶层调用 Hook,不要在循环、条件或嵌套函数中调用 Hook。
  • 仅从 React 功能组件调用 Hook。不要从常规 JavaScript 函数调用 Hook。(还有另一个有效的地方来调用 Hook,即你的自定义 Hook。)

这里(https://www.npmjs.com/package/eslint-plugin-react-hooks)提供了一个 linter 插件来自动执行这些规则,这些规则乍看起来有些令人疑惑,但它们对 Hook 的良好运行至关重要。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

为什么要在 React 中引入 Hooks?

至于为何要在 React 中引入 Hooks,React 官方给出了答案:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

Hooks 解决了 React 中各种看似不相关的问题,这些问题是我们在开发和维护数以万计的组件时遇到的。无论你是在学习 React,还是每天在使用它,还是选择使用具有类似组件模型的其他库,你都可能会发现这类问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

难以在组件之间重用有状态逻辑

React 没有提供可将可重用行为“附加”到组件的方法。如果你用过 React 一段时间,可能会对渲染 prop 和高阶组件等模式比较熟悉,它们试图解决这个问题。但是这些模式要求你在使用它们时重构组件,这可能很麻烦,并且代码会变得难以维护。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

如果你看一下 React DevTools 中的典型 React 应用程序,你可能会发现“包装器地狱”,组件被层层的提供者、消费者、高阶组件、渲染 prop 和其他抽象组件组包围。虽然我们可以在 DevTools 中过滤掉它们,但这反应了一个更深层次的问题:React 需要一个更好的原语来共享有状态逻辑。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

使用 Hooks,你可以从组件中提取有状态逻辑,可以进行独立测试和重用。Hooks 允许你在不更改组件层次结构的情况下重用有状态逻辑。这样可以轻松地在多个组件之间或与社区共享 Hooks。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

复杂的组件变得难以理解

我们通常维护的组件都先从简单的开始,然后逐渐加入无法管理的状态逻辑和副作用。每个生命周期方法通常包含不相关逻辑的混合。例如,组件可能会在 componentDidMount 和 componentDidUpdate 时获取数据。不过,相同的 componentDidMount 方法可能还包含一些设置事件监听器的无关逻辑,并在 componentWillUnmount 中执行清理工作。一起更改的相互关联的代码会被拆分,但完全不相关的代码最终会组合在一个方法中。这样就很容易引入错误和导致不一致。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

在很多情况下,很难将这些组件分解为更小的组件,因为状态逻辑到处都是。测试它们也很困难。这是很多人更喜欢将 React 与单独的状态管理库相结合的原因之一。不过,这通常会引入太多的抽象,要求你在不同的文件之间跳转,让重用组件变得更加困难。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

为了解决这个问题,Hooks 让你可以根据相关的部分将一个组件拆分为较小的函数,而不是基于生命周期方法进行强制拆分。你还可以选择使用 reducer 来管理组件的本地状态,以使其更具可预测性。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

类让人和机器感到困惑

根据我们的观察,类是学习 React 最大的障碍。你必须了解 JavaScript 中的 this 是怎么回事,这与它在大多数语言中的使用方法有很大不同。你必须记住绑定事件处理程序。人们可以很好地理解 prop、状态和自上而下的数据流,但对类的使用仍然感到很挣扎。React 中的函数和类组件之间的区别以及何时使用哪个组件在经验丰富的 React 开发人员之间也存在分歧。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

另外,React 已经推出了大约五年时间,Facebook 希望 React 在未来五年充满活力。正如 Svelte、Angular、Glimmer 和其他项目所表明的那样,预编译组件具有很大的潜力。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

最近,他们一直在尝试使用 Prepack(https://prepack.io/)进行组件折叠,我们已经看到了充满希望的结果。不过,他们发现类组件的无意识模式可能会使这些优化回退。在类上应用现今的一些工具时也存在一些问题。例如,类难以进行 minify,并且类会导致热重载变得不可靠。他们希望提供一种 API,使代码更有可能保持在可优化的路径上。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

为了解决这些问题,Hooks 让你可以在不使用类的情况下使用更多的 React 特性。从概念上讲,React 组件很接近于函数。Hooks 拥抱函数,但不会以牺牲 React 精神为代价。Hooks 提供了命令式的编程方式,不需要你学习复杂的函数式或反应式编程技术。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

例子:https://reactjs.org/docs/hooks-overview.html文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

逐步采用策略

我们知道,React 开发人员专注于产品,他们没有时间研究发布的每个新的 API。Hooks 是新东西,在学习或采用它们之前先等待更多的示例和教程,这样可能会更好。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

我们也知道为 React 添加新原语的标准是非常高的。对于好奇的读者,这里准备了一个详细的 RFC(https://github.com/reactjs/rfcs/pull/68),其中包含更多的细节,并为特定设计决策和现有相关技术提供了额外的视角。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

关键的是,Hooks 可以与现有代码同时存在,因此你可以逐步采用它们。React 官方正在分享这个实验性的 API,以便从社区中那些有兴趣打造 React 未来的人那里获得早期反馈,将公开进行 Hooks 的迭代。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

最后,没有必要急于使用 Hooks。建议避免任何“重大的重写”,特别是对于复杂的现有类组件来说。进入“Hooks 思考”模式需要精神上的转变。根据经验,最好先在非关键的新组件中练习使用 Hooks,并确保团队中的每个人都能适应。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

React 官方打算让 Hooks 涵盖所有与类相关的用例,但在可预见的未来,他们将继续支持类组件。在 Facebook 有数万个类组件,他们表示绝对没有计划重写它们。相反,他们开始在新代码中使用 Hooks。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

怎样使用 Hooks?

假设我们正在尝试编写一个 Counter 组件,正常的实现如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

React将引入Hooks,使用有什么好处?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

而基于 Hooks 的实现将如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

React将引入Hooks,使用有什么好处?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

使用 Hooks 的好处非常明显:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html

  • 减少代码实现;
  • 共享逻辑,可以将逻辑解耦。
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/7578.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/7578.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定