抖音技术能力大揭密!钜惠大礼、深度体验,尽在火山引擎增长沙龙,就等你来! 立即报名>> 了解详情
写点什么

使用 React Hooks 代替类的 6 大理由

2020 年 10 月 12 日

使用React Hooks代替类的6大理由

React hooks 已经出来有一段时间了,但是许多 React 开发人员对它们的态度并不是很积极。我发现这背后主要有两个原因。第一个原因是许多 React 开发人员已经参与了一个大型项目,需要付出巨大的努力才能迁移整个代码库。另一个原因是大家对 React 类已经很熟悉了。有足够经验的话,继续使用类会感到更自在。


在本文中,我们将探讨考虑使用 React Hooks 的六个原因。


1. 扩展函数式组件时,不必将其重构为类组件

经常会有这种情况,那就是一个 React 组件从一个函数式组件开始开发,一开始这个函数式组件只依赖 props,后来演变为具有状态的类组件。从函数式组件更改为类组件需要一些重构工作,具体取决于组件的复杂程度。


使用 React Hooks 时,由于函数式组件具有进入状态的能力,因此重构工作会非常少。来看以下示例,这是一个哑组件,它会显示一个带有计数的标签。


export function ShowCount(props) {  return (    <div>       <h1> Count : {props.count} </h1>    </div>  );}
复制代码


ShowCount 函数式组件


假设我们需要通过点击鼠标来增加计数,并假设这只会影响这一个组件。第一步,我们需要将状态引入组件。我们看一下如何使用基于类的方法。


export class ShowCount extends React.Component {  constructor(props) {    super(props);    this.state = {      count: 0    };  }  componentDidMount() {    this.setState({      count: this.props.count    })  }  render() {    return (      <div>         <h1> Count : {this.state.count} </h1>      </div>    );  }  }
复制代码


引入状态后的 ShowCount 组件


如果使用 hooks,则相同的组件会是下面这样。


export function ShowCount(props) {  const [count, setCount] = useState();  useEffect(() => {    setCount(props.count);  }, [props.count]);  return (    <div>      <h1> Count : {count} </h1>    </div>  );}
复制代码


带 hooks 的 ShowCount 组件


2. 你不必再担心“this”了

人类和机器都会因为类而困惑


上面这句话来自React文档。造成这种混乱的原因之一是 this 关键字。如果你熟悉 JavaScript,就会知道 JavaScript 中的 this 与其他语言并不完全一样。但在 React Hooks 这边,你完全不必操心 this 了。这对初学者和经验丰富的开发人员来说都是有益的。



分别使用 hooks 与类访问状态的对比


根据上面的示例,你可以看到访问状态时我们不再需要使用“this”。这样大家就都不会感到困惑了。


3. 不再有方法绑定

现在,对于前面提到的那个 ShowCount 组件,我们将引入一种方法,当用户单击标签时,该方法可以更新状态计数。


export class ShowCount extends React.Component {  constructor(props) {    super(props);    this.state = {      count: 0    };    this.handleClickEvent = this.handleClickEvent.bind(this);  }  componentDidMount() {    this.setState({      count: this.props.count    });  }  handleClickEvent() {    this.setState({count: this.state.count + 1});  }  render() {    return (      <div>        <h1 onClick={this.handleClickEvent} > Count : {this.state.count} </h1>      </div>    );  }}
复制代码


具有 Click 事件处理程序的 ShowCount 组件


我们引入了 handleClickEvent 方法。要使用它,首先我们必须将其绑定到该组件的 this 上。


this.handleClickEvent = this.handleClickEvent.bind(this);
复制代码


我们必须这样做,因为执行方法时的执行上下文是不一样的。对于初学者来说,这可能有点难以理解。


除了绑定所有方法之外,还有一些语法提案可以解决这个问题。例如,我们可以将这个函数重写为一个箭头函数。


handleClickEvent = () => {  this.setState({count: this.state.count + 1});}
复制代码


让我们看看如何使用 hooks 实现相同的功能。


export function ShowCount(props) {  const [count, setCount] = useState();  useEffect(() => {    setCount(props.count);  }, [props.count]);  function handleClickEvent() {    setCount(count + 1);  }  return (    <div>      <h1 onClick={handleClickEvent}> Count : {count} </h1>    </div>  );}
复制代码


hooks 中带有事件处理程序的 ShowCount 组件


如你所见,我们只添加了这个函数。另外你可能会注意到,当我们使用事件处理程序时,已经在模板中删掉了 this。


onClick={ handleClickEvent }
复制代码


4. 更容易分离逻辑与 UI,从而使两者都更加可重用

使用 hooks 时,逻辑和 UI 更容易分离。无需 HOC 或渲染 props。hooks 用更少的样板和更直观的 UI 和逻辑组合来优雅地做到这一点。


当使用Bit之类的工具和平台共享组件时,这种“优雅的分离”尤其重要,因为每个(独立共享的)组件在不同应用程序之间都会更容易理解、维护和重用。



Bit.dev 上的共享 React 组件


5.将相关逻辑放在同一位置

复杂的组件会变得难以理解


使用基于类的方法,我们会有不同的生命周期方法,例如 componentDidMount 和 componentDidUpdate 等。让我们考虑一种情况,就是在 componentDidMount 中订阅服务 A 和 B,然后在 componentWillUnmount 中取消订阅它们。随着时间的流逝,两种生命周期方法中都会包含许多逻辑,并且很难跟踪挂载与卸载过程中哪些部分是相关联的。


为了演示这一点,我们来创建一个基于 RxJs 的服务来获取计数。我们将使用这个服务来更新 ShowCount 示例中的计数。请注意,由于不再需要在 click 事件中更新组件,我们将删除 handleClickEvent。


import { Subject } from "rxjs";export function getCounts() {  const subject = new Subject();  let count = 0;  const interval = setInterval(() => {    if (count > 10 || subject.isStopped) {      clearInterval(interval);      subject.complete();    }    subject.next(count++);  }, 1000);  return subject;}
复制代码


getCounts 函数


import { getCounts } from "./reactive-service";export function ShowCount(props) {  const [count, setCount] = useState();  useEffect(() => {    const countServiceSubject = getCounts();    countServiceSubject.subscribe((count) => {      setCount(count);    });    return () => {      countServiceSubject.unsubscribe();    };  }, []);  return (    <div>      <h1> Count : {count} </h1>    </div>  );}
复制代码


带有 Effect hook 中 getCounts 方法的 ShowCount 组件


你可以看到在 useEffect 内部,我们包括了订阅以及相应的取消订阅逻辑。同样,如果我们需要引入更多的服务订阅或不相关的逻辑,则可以添加多个 useEffect 块,在逻辑上分离不同的关注点。


import { getCounts } from "./reactive-service";export function ShowCount(props) {  const [count, setCount] = useState();  const [secondCount, setSecondCount] = useState(0);  useEffect(() => {    const countServiceSubject = getCounts();    countServiceSubject.subscribe((count) => {      setCount(count);    });    return () => {      countServiceSubject.unsubscribe();    };  }, []);  useEffect(() => {    setSecondCount(secondCount + 1);  }, []);  return (    <div>      <h1> Count : {count} </h1>      <h1> Second Count: {secondCount} </h1>    </div>  );}
复制代码


多个 useEffect 块可分离不相关的逻辑


6. 在组件之间共享状态逻辑

使用基于类的方法时,我们很难在组件之间共享状态逻辑。考虑两个组件,这两个组件都必须从两个不同的数据源获取、排序和显示数据。即使两个组件具有相同的功能,它们之间也很难共享逻辑,因为这些组件具有不同的源和状态。


虽然我们可以使用渲染props高阶组件来解决这个问题,但由于我们必须重构组件,这会引入额外的成本,到头来会变得更麻烦。


React Hooks 又是怎么做的呢?

使用自定义 React Hooks,你可以提取这些可重用的状态逻辑并分别测试它们。


我们可以从 ShowCount 示例中提取一个自定义 hook。


import { useState, useEffect } from "react";export function useCount(serviceSubject) {  const [count, setCount] = useState();  useEffect(() => {    serviceSubject.subscribe((count) => {      setCount(count);    });    return () => {      serviceSubject.unsubscribe();    };  }, [serviceSubject]);  return [count, setCount];}
复制代码


自定义 hook 来共享状态逻辑


使用上面的自定义 hook,我们可以像下面这样重写 ShowCount 组件。注意,我们必须将数据源作为参数传递给这个自定义 hook。


import { useCount } from "./use-count";export function ShowCount(props) {  const [count, setCount] = useCount(props.serviceSubject);  useEffect(() => {    setCount(-1);  }, [setCount]);  return (    <div>      <h1> Count : {count} </h1>    </div>  );}
复制代码


ShowCount 组件,带有数据源参数


请注意,我们在父组件,而不是 ShowCount 组件中调用 getCounts。否则,serviceSubject 每次运行 ShowCount 时都将有一个新值,而我们将无法获得预期的结果。


结论

切换到 React Hooks 的理由有很多,但我已经提到了其中一些最令人信服的原因,这些足够让我改用 React Hooks 了。如果查看官方文档,你会发现 React Hooks 有很多有趣的功能。请大家也谈一谈自己的 React Hooks 之旅吧。


你可以在此处找到完整的源代码。


原文链接:


https://blog.bitsrc.io/6-reasons-to-use-react-hooks-instead-of-classes-7e3ee745fe04


2020 年 10 月 12 日 17:371902

评论

发布
暂无评论
发现更多内容

JVM笔记 -- JVM经历了什么?

秦怀杂货店

Java JVM

带你全面认识CMMI V2.0(一)

渠成CMMI

项目管理 CMMI

我用一个小小的开放设计题,干掉了40%的面试候选人

架构精进之路

Web 安全 软件设计 3月日更

mysql 四种隔离级别

Sakura

28天写作 28天挑战 3月日更

轻量级的接口自动化冒烟框架

小小娃爱吃甜食

自动化 测试 框架 自动化部署

百度×TCL丨鸿鹄语音芯片首次在家电行业量产!

百度大脑

百度 语音识别 百度大脑 智能家居 百度智能云

HashData与HDFS的高效数据交换

HashData

HashData外部表的实现与应用

HashData

万字长文,肝了一下午的线程池详解!

JavaFish

Java 多线程 线程池 线程池工作原理

【2021 ECUG Con】聚势而来,与你相约花开时

小剑客

区块链 云计算 大数据 开源 go语言

什么是VXLAN?为什么需要VXLAN?

华为云开发者社区

网络 虚拟化 VLAN VXLAN 报文

【LeetCode】 基本计算器 II Java题解

HQ数字卡

算法 LeetCode 28天写作 3月日更

刷爆LeetCode!字节技术官亲码算法面试进阶神技太香了

程序员小毕

Java 数据结构 面试 算法 字节

阿里P8手把手教你!万字Android技术类校招面试题汇总,附赠课程+题库

欢喜学安卓

android 程序员 面试 移动开发

HashData多集群共享统一存储架构

HashData

全国大学生智能汽车竞赛-百度线下赛题发布!封狼居胥,等你来战!

百度大脑

人工智能 百度 比赛 飞桨 AI Studio

2021年4款好用的音乐编曲软件推荐

奈奈的杂社

ZooKeeper 的选举机制,你了解多少?

云流

架构 分布式

《精通比特币》学习笔记(第七章)

棉花糖

区块链 学习笔记 3月日更

数字经济时代,区块链能否担当产业数字化转型核心赋能者?

旺链科技

区块链数字经济 区块链发展

百度文心多项任务分数刷新GLUE榜单,NLP界的“MVP”再次夺冠

百度大脑

自然语言处理 百度 文心 ERNIE

1500道算法面试题:Github上标星86.7K!直接火遍全网

比伯

Java 编程 程序员 架构 面试

一周信创舆情观察(3.1~3.7)

统小信uos

音乐信息检索:理性解构音乐

阿里云视频云

阿里云 算法 音频

大作业

胡益

Flink SQL CDC 实践以及一致性分析

Apache Flink

flink

Weblogic11g安装部署-winserver篇

xiezhr

中间件 Windows Server 3月日更 weblogic

助我拿到37KOffer,这份阿里巴巴890页Redis笔记可谓功不可没

Java架构追梦

Java redis 阿里巴巴 架构 java面试

阿里P8亲自教你!2021Android大厂面试知识分享,实战篇

欢喜学安卓

android 程序员 面试 移动开发

江苏交通控股打造IT架构云转型下的智慧交通

HashData

快了何止300%?阿里巴巴Java优化:设计+程序+并行+JVM+工具

Java架构追梦

Java 阿里巴巴 架构 面试 性能优化

Study Go: From Zero to Hero

Study Go: From Zero to Hero

使用React Hooks代替类的6大理由-InfoQ