什么是React Hooks,为什么我需要它们?

我认为可以这样说,当涉及到Hooks时,你会发现有三种类型的React开发者:热爱这个想法、讨厌这个想法,以及对整个事情感到困惑。

如果你是那些想知道这些噪音是关于什么的人,这篇文章将为你带来急需的解脱。

那么,喝杯咖啡☕,靠在椅子上,享受吧!

快速变化和突如其来的巨大转变并不会困扰前端开发者。他们已经意识到抵抗是徒劳的,并且已经准备好每年学习一种新的CSS framework,每周学习一种新的JavaScript framework(因为它们似乎以惊人的速度涌现),并且每两年完成一次个人和工作相关的Web应用程序的重写。

然而,没有人预料到Facebook的React团队带来的Hooks的巨大改变。突然间,React developers被告知用类构建应用程序的旧方法并不是最好的想法;他们现在应该采用这个闪亮、新颖、功能强大的东西,叫做Hooks。

关于是否每个人都应该将他们的React应用程序的类重写为Hooks,React核心团队劝阻了他们,称这样做需要太多的努力。但他们非常强调类组件进入维护模式,而Hooks是每个人都想要的光明未来。

嗯……好吧……

这让大家都摸不着头脑。Hooks有一个相当复杂的表面积要覆盖,思维模式被颠倒,学习曲线(带有许多“惊喜!”的时刻)陡峭。在撰写本文的时刻,Hooks已经成为React应用程序中的标准。了解它们对于新开发者来说是必须的(同样,遗憾的是,了解类组件也是必须的,因为它们在许多近期/旧项目中使用)。

但总体情况仍然模糊不清;那些在某种程度上理解hooks的人宣称自己是“专家”,而其他人还在摸索中。在高级开发者中,几乎所有人都认为Hooks是一个更好的解决方案,而少数人则认为它们只是他们工具库中的另一种武器。

关键是,风向正在朝着Hooks的方向吹,无论你是否喜欢它们,了解它们对你的职业生涯来说都是一个巨大的帮助。让我们继续了解关于Hooks的两个基本事实:1)它们是什么;2)为什么你需要它们。

然而,我觉得我必须强调本文的结构。

通常来说,先解决一个新事物的“是什么”然后再谈“为什么”是有道理的。然而,由于这是一篇给困惑的React开发者(或者说一般的前端开发者)阅读的文章,我认为通过解释Hooks解决了什么样的问题更为重要。做到这一点后,我们头脑中的紧张感将会消解,我们将了解Hooks背后的哲学和实用主义。然后,被这个想法所说服(或者不被说服,尽管如果你希望成为/继续成为React开发者,这并不会有太大帮助),我们可以概述一下Hooks是什么。

为什么创建React Hooks?

Hooks的创建并不仅仅因为Facebook的一些优秀工程师感到不安。你知道,React是Facebook自己使用的(而且非常频繁),所以从第一天起,他们就致力于将React发展成最适合他们需求(可组合、高性能的前端工作)的方向。在编写和维护了成千上万的组件后,React团队决定类组件并不可行。

让我们看看(由Facebook和其他人提出的)使开发者不喜欢类组件的各种原因。

JavaScript类是一个谎言。

这是我对核心语言发展方向的个人抱怨。JavaScript可能看起来像是受C语言启发的花括号语言,但相似之处就到此为止了。但是,ES5/ES6版本的语言添加了“类”。突然间,“现代”JavaScript代码让来自其他语言的开发人员感到亲切:

class ShoppingCart extends BasicShoppingCart {
	constructor(items) {
    	super(items);
        this.items = items;
    }
    
    getTotalPrice() {
    	let price = 0;
        for (let item of this.items) {
        	price += item.price;
        }
        return price;
    }
    
    // and so on
}

类,子类,继承层次结构,构造函数,getter,setter,静态成员(粗略来说),extendsnew关键字 – 这些东西让经验丰富的面向对象编程架构师心满意足(恕我直言,对他们的经验和能力表示敬意)。就像在语言名称中加入“Java”(在早期被称为LiveScript时)一样,关键字“class”也许旨在巩固地位并融入其他非常相似的语言群体中(PHP,Perl,Python,Ruby,Java – 几乎可以无缝地从一个过渡到另一个)。

但是,在JavaScript中,类是一种谎言(“可恶”的类型)。当JavaScript引擎运行代码时,它没有类的概念;因此,需要使用类似于Babel这样的工具将“现代”且“好看”的类转换为普通函数。如果涉及继承,它会转换为JavaScript中唯一可能的继承类型 – Prototypal Inheritance

因此,当我们闭上眼睛编写基于类的代码时,我们在欺骗自己,并使我们的立场在最终我们对表面知识的掌握将会反噬我们的那一天变得更加脆弱。

嗯,这很棘手!

尽管试图在JavaScript中隐藏基本关键字this,但这个问题在React类(以及一般的JavaScript类)中经常出现。在几种用例中,组件函数因为在执行的那一刻没有绑定到正确的上下文而抛出错误。要解决这个问题,您必须提前将它们绑定(详细信息请阅读this),或者在回调中使用箭头函数显式地绑定到React上下文。这肯定不是一个终结者,但它确实增加了认知负担,因为它又增加了另一件需要时刻注意的事情;当然,这也是每个新的React开发人员都会遇到的问题。

大惊小怪

代码重用是software development中的一个常见目标。类可能在其他上下文(和语言)中促进代码重用,但在React中,它们在代码共享方面引入了问题。这是React世界早期的一个重要争论/兴趣点,社区最终演进出了像高阶组件和渲染道具这样的解决方案来应对这个问题。基本思想是将组件传递给其他组件,这些组件“包裹”一些功能。任何接触过使用这些“解决方案”的代码的人都知道其中的痛苦,并且不想再做一次(包括我自己)。

阅读本指南以了解React rendering behavior

您只需要阅读官方文档Higher-Order Components,就可以亲自看到整个想法是多么笨拙。在实际项目中,通常需要共享多个代码片段,这很容易导致多层组件包装层次结构。这是那种即使作者几周后也无法理解的代码!是的,当使用React类时,代码重用并非不可能实现,但它很笨拙而且令人困惑。

属性传递

属性传递(prop drilling)是您在组件层次结构中具有很高的属性时面临的问题(至少在原始的React中),它需要在较低层次的组件中使用。以下是一个示例:考虑典型Web应用程序中的用户个人资料,通常显示在页眉中。现在,假设用户的详细信息也需要在页脚组件中使用,例如“到目前为止,您已经完成了34次交易|在这里获得更多有趣的统计数据”。如果您正在使用类,如何将个人资料信息提供给页脚?嗯,我认识的一些React开发人员可能会说“算了吧!”并在页脚中进行额外的API调用,但这是一种糟糕的做法。

唯一的方法也是唯一的选择:从组件向其子组件传递个人资料prop,直到它达到页脚组件。是的,这是一个繁琐的过程,而且是的,它使代码难以阅读(因为在中间组件中,您需要在心理上忽略该属性,因为它除了在下层传递时没有任何用处)。这种自上而下链式处理属性的方法被称为属性传递(prop drilling),在React世界中被称为一种可怕的现象。

当使用类时,React开发人员会使用Redux等工具来解决此问题,但如果您不打算将Redux用于所有内容,那么这就是太多的前期投入。使用Hooks,React发布了一个名为Context的功能,专门用于此用例。现在,Context也可以与类一起使用,但很难忽略其笨拙性;此外,使用Hooks可以轻松使用多个上下文。

要学习的东西更少

这听起来似乎自相矛盾,React团队也承认这个观点。他们正在引入一种全新的写法React apps;我们被告知不应该重写或抛弃现有的基于类的代码,但React团队告诉我们要学习的东西更少!

“有人射了我吧!”

实际上,问题在于,短期内,React生态系统中的整体复杂性和混乱将激增(确实如此,因为新人学习React需要学习类、高阶组件(HoC)、Hooks、Context、Redux和许多其他库以及其边缘案例)。但更重要的是,如果Hooks被证明是一个成功的概念,从长远来看,许多概念可以被删除,只留下一小部分核心Hooks、函数组件和其他不多的东西。这不会很快发生(仅仅是因为现有代码基于类的数量),但这将是我们最终的归宿。

合理的组件“升级”

React中一个常见的困境是决定一个新组件是应该写成类还是函数。为了最小化复杂性,通常的做法是从一个无状态的函数组件开始。然后,如果有时候你认为该组件需要管理一些状态或需要访问更多功能(例如生命周期方法),您会将其转换为基于类的组件。但是您只需要删除所有组件代码,重新思考方法,然后编写基于类的版本。不好玩,是吧。

使用Hooks,这样的组件“升级”更加简单和顺畅:一个函数组件即使承担了许多职责后仍然是一个函数组件;Hooks中没有生命周期方法,尽管一些类似的功能是可用的;最后,任何常见功能都可以提取到单独的hooks中,并由其他组件重复使用。您有没有发现这种情况下的美之所在?—一切都是函数或Hook(它也是一个函数,但出于开发的目的,我们可以区别对待),在尝试将square放入圆孔中时不涉及任何“猴子买椰子”的问题。😀

所以,我们就是这样。Hooks并不针对任何一件事情,而是一种重大的范式转变。是的,这很不方便,但开发者的体验结果要好得多(与使用类的React相比)。

现在我们解决了“为什么”的问题,让我们转向真正的Hooks。

React中的Hooks是什么?

Hooks很难定义,但同时也很容易定义。容易的版本是你可以在官方文档的初始句子中找到的:Hooks是一种在没有类的情况下编写React组件的方法;它们还为您提供了“hook”到React核心功能(如状态、控制重新渲染等)的方法。

这并没有帮助太多,对吧?!

因为第一次接触Hooks时,它对我没有帮助。要理解Hooks的真正含义,您必须进行长期和耐心的研究(而且它们没有短缺!),使用它们构建应用程序(甚至重建过去的应用程序),遇到特殊情况等等。

但是为了让您有一种“感觉”,以下是使用Hooks的代码样式。请记住,所有组件都是函数式的,与组件相关的代码都在其中定义。

import React, { useState } from 'react';

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

  return (
    
      

您点击了{count}次

); }

是的,这就是我们在使用类时写过无数次的Counter组件!但是您可以看到差异是多么大:构造函数消失了,访问和更改状态更简单和模块化(您可以使用任意多个useState()调用来管理不同的状态片段),代码更短。在许多情况下,生成的代码比基于类的组件要短得多-简单地因为Hooks简洁地捕捉并提供了相同的功能。

有几种类型的hooks,useState()只是其中之一。如果您对它们有多少种和它们的功能感兴趣,请查看官方文档中的docs

结论

Hooks给React生态系统带来了巨大的变化,并且已经成为一种不可或缺的存在。它们简化了组件结构、架构、层次结构、代码重用等等。虽然有一些非常有声望的批评者,但总体接受程度非常高,未来看好。

这是React团队的一项基本贡献,可能会对其他框架产生影响并产生根本性的影响。front-end development

接下来,请查看如何开始使用React Storybook

类似文章