【墙裂推荐】Talking about hooks(上)

简介: 从React16.8开始,Hooks API正式被React支持,而就在最近,Vue作者尤雨溪翻译并发布了一篇自己的文章《Vue Function-based API RFC》,并在全文开头强调这是Vue 3.0最重要的RFC,并在文中提到Function-based API 受 React Hooks 的启发,提供了一个全新的逻辑复用方案。

从React16.8开始,Hooks API正式被React支持,而就在最近,Vue作者尤雨溪翻译并发布了一篇自己的文章《Vue Function-based API RFC》,并在全文开头强调这是Vue 3.0最重要的RFC,并在文中提到


Function-based API 受 React Hooks 的启发,提供了一个全新的逻辑复用方案。


可以简单的理解为,React 和 Vue 为了解决相同的问题,基于不同的技术实现了相似的API。所以本文也将结合两种框架各自的特点,简单讲讲个人对Hooks的理解。


在未来版本的规划里,React并不如Vue激进,React的文档里专门提到


并没有从 React 中移除 class的计划。


而Vue却采取了不同的升级策略,做好了抛弃大部分历史语法的准备


  • 兼容版本:同时支持新 API 和 2.x 的所有选项;


  • 标准版本:只支持新 API 和部分 2.x 选项。


为什么我们不再需要Class Component?


为了回答这个问题,我们先看看之前和现在的React组件划分产生了哪些变化。

1. 既然本来就有函数组件,开始为什么引入class组件?


早期的React组件可以依据“有没有状态(state)”分为


// 无状态组件
const Welcome = (props) => <h1>Hello, {props.name}</h1>;
// 有状态组件
class Welcome extends React.Component {
    constructor(props) {
        super(props);
        this.state = {name: 'KuaiGou'};
    }
    render() {
        return <h1>Hello, {this.state.name}</h1>;
    }
}


虽然class也可以不添加状态,但想要使一个函数组件具有状态,不得不将其转换成class组件。


直观来看,好像造成这种差异是因为在class里,我们能通过this保存和访问“状态(state)”,而函数组件在其作用域内难以维持“状态(state)”,因为再次函数运行会重置其作用域内部变量,这种差异导致了我们“不得不”使用class至今。


看来如何解决函数组件保存state的成了移除class这种“难以理解”的关键。


2. 那Hook是如何保留组件状态的?


这就是我看见Hook API产生的第一个疑问。其实在React里,这并不是问题,熟悉React Fiber的同学应该知道,事实上state是保存到Fiber上的属性memoizedState上的,而并不算是class的this.state上。那状态问题就迎刃而解了,如果函数组件同样访问Fiber上的memoizedState属性,就可以解决这个问题。


基于Fiber架构,解决这个问题非常容易,将memoizedState看作一个普通的变量,那么Hook的原理就容易理解和实现了。


在文章[译] 理解 React Hooks中提到


记住,在 Hooks 的实现中也没有什么“魔术”。就像 Jamie 指出的那样,它像极了这个:


let hooks = null;
export function useHook() {
    hooks.push(hookData);
}
function reactsInternalRenderAComponentMethod(component) {
    hooks = [];
    component();
    let hooksForThisComponent = hooks;
    hooks = null
}


如Fiber一样,React实际上使用链表代替了数组这种数据结构,依次执行Hook,有兴趣的同学可以去看下React源码。


可是,class目前也能良好的支撑业务迭代,到底有什么动力去重新学习Hooks?


3. 为什么我们需要Hooks?


针对这个问题,React文档提到了下面三点:


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


  • 复杂组件变得难以理解


  • 难以理解的 class


其实我觉得第三点就是来凑数的,毕竟React推出至今一直用着class,再难用各位也都会了,会者不难难者不会嘛(反正对于刚入前端坑那时候的我来说,没有啥是容易的)。


那就回答下一个问题,目前基于class实现的生命周期函数,是否真的会造成逻辑难以复用?


答案是NO


无论高阶组件或是render props,都提供了很好的方式来达到聚合业务逻辑的目的,业务逻辑并不会被生命周期“分割”。


那到底是哪里引入了复杂度?熟悉套娃的同学...呸


熟悉Ajax、Promise的等异步API的同学可能还记得“回调地狱”。类似的,高阶函数、render props等也极容易造成“嵌套地狱”,结合装饰器、函数式的compose等嵌套起来才是真的爽...一直嵌套一直爽...


但是,无论是什么地狱肯定是不好的,那一起来看最后一个问题。


复杂组件变得难以理解


之所以回避前两个问题,是因为我个人认为,无论是class还是HOC,它们都很好的解决了它们需要解决的问题,虽然生命周期函数将很多业务逻辑拆分的七零八碎,但是HOC却依旧能把它们集合在一起,仅考虑保留生命周期而言,就像Function-based一样(这是后话)。


所以我们换一个思路不难发现,真正的问题是在于它们在抽象业务逻辑的时候貌似引入了不必要的概念,才使得逻辑复用困难和难以理解。


这些概念导致了过多的嵌套,加深了组件层级,层级之间互相牵扯,就像我现在兜里的耳机线一样。


Hook独特之处在于化繁为简。


真正繁琐的是层级与层级之间的关系,我将借用React文档关于自定义Hook的例子说明这个问题


import React, { useState, useEffect } from 'react';
// 通过friendID订阅好友状态
function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });
  return isOnline;
}


相关文章
|
机器学习/深度学习 Web App开发 数据可视化
过节福利 | MMCV Hook 超全使用方法(下)
在训练过程中,通常有十个关键位点,如下图所示,从训练开始到结束,所有关键位点已用红色标出,共有 10 个。我们可以在这十个位点插入各种逻辑,例如加载模型权重、保存模型权重。而我们将同一类型的逻辑组织成一个 Hook。因此,MMCV 中 Hook 的作用就是训练和验证模型时,在不改变其他代码的前提下,灵活地在不同位点插入定制化的逻辑。
1843 0
过节福利 | MMCV Hook 超全使用方法(下)
|
前端开发 JavaScript
Components make life easier(组件复用让生活更美好)
Components and Props Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.
84 0
|
Web App开发 JavaScript 前端开发
Modern模式引发qiankun的一场“命案”
前沿:文章的起源在于开发环境中使用qiankun框架,父应用加载子应用遇到一则报错 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec 直接的翻译意思就是加载模块脚本失败:服务器以非JavaScript MIME类型“text/html”去响应。而也是这个问题引发了我的思考,到底是什么问题导致?
960 0
Modern模式引发qiankun的一场“命案”
过节福利 | MMCV Hook 超全使用方法(上)
在训练过程中,通常有十个关键位点,如下图所示,从训练开始到结束,所有关键位点已用红色标出,共有 10 个。我们可以在这十个位点插入各种逻辑,例如加载模型权重、保存模型权重。而我们将同一类型的逻辑组织成一个 Hook。因此,MMCV 中 Hook 的作用就是训练和验证模型时,在不改变其他代码的前提下,灵活地在不同位点插入定制化的逻辑。
617 0
过节福利 | MMCV Hook 超全使用方法(上)
|
设计模式 前端开发 JavaScript
【墙裂推荐】Talking about hooks(下)
从React16.8开始,Hooks API正式被React支持,而就在最近,Vue作者尤雨溪翻译并发布了一篇自己的文章《Vue Function-based API RFC》,并在全文开头强调这是Vue 3.0最重要的RFC,并在文中提到 Function-based API 受 React Hooks 的启发,提供了一个全新的逻辑复用方案。
|
前端开发
《the Great Gatsby》Day 26
Gatsby告诉Daisy,她只要说自己从未爱过Tom,便能就此解脱,幸福地和自己在一起;但是当Tom说出曾经的种种,回忆淹没了Daisy,她没办法违背自己的内心——她曾深爱过Tom。Daisy说自己还是会离开Tom,Tom情急之下说出了Gatsby光鲜外表背后的那些不光彩的勾当。Daisy再一次恳求Tom带她回家,Tom却让Gatsby开车送她
104 0
《The Great Gatsby》Day 22
《The Great Gatsby》Day 22 2.大概内容 一度是灯火通明的Gatsby家,在一个夏夜突然暗淡下来,那些怀着希望而来的人们,看到这副景象也都失望地离开了。。。Nick开始以为Gatsby生病了或是去了外地,后来才
95 0
《The Great Gatsby》Day 18
Gatsby进屋后,尴尬又紧张地依靠在壁炉旁,不知该如何打破沉默,Nick看到两人都很拘谨的样子,说自己有点事就出门了。Nick回屋时看到Gatsby和Daisy正坐在沙发上小声而热切地交谈着,含情脉脉地望着对方,连Nick回来都不知道。雨停后,Gatsby又邀请Daisy和Nick去自己家参观。 3.好词佳句 (1)The rain was still falling,but the darknes
113 0
《The Great Gatsby》Day 12
舞会快结束的时候,Jordan和Gatsby也从书房出来了,Jordan告诉Nick她刚刚听到了最不可思议的事,但是又故意卖关子不肯说说是什么;她被伙伴们簇拥着上了车,和Nick告别时叮嘱Nick一定要给她打电话,Nick和Gatsby道别后也回家了。生活一天天过去,Nick也渐渐爱上了纽约。
87 0
《The Great Gatsby》Day 14
大致内容 一天早晨,Gatsby开着他的定制轿车出现在Nick家门口,要带他一起去城里吃饭;在路上,Gatsby向Nick讲述自己的故事(他出身在中西部一个富有的家庭,在美国长大,又去了牛津三一学院读书,后来家人相继去世,他便继承了大笔遗产;后来参军,英勇善战,甚至获得了黑山共和国的荣誉勋章。)Gatsby还说有时要拜托Nick,但又执意要等到午饭后才说。 3.好词佳句
121 0