React Hooks究竟是什么呢?
摘要: React Hooks原理解析。
- 原文:快速了解 React Hooks 原理
- 译者:前端小智
我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件却不能?
React 早期版本,类组件可以通过继承PureComponent
来优化一些不必要的渲染,相对于函数组件,React 官网没有提供对应的方法来缓存函数组件以减少一些不必要的渲染,直接 16.6 出来的 React.memo
函数。
React 16.8 新出来的Hook
可以让React 函数组件具有状态,并提供类似 componentDidMount
和componentDidUpdate
等生命周期方法。
类被会替代吗?
Hooks
不会替换类,它们只是一个你可以使用的新工具。React 团队表示他们没有计划在React中弃用类,所以如果你想继续使用它们,可以继续用。
我能体会那种总有新东西要学的感觉有多痛苦,不会就感觉咱们总是落后一样。Hooks
可以当作一个很好的新特性来使用。当然没有必要用 Hook 来重构原来的代码, React团队也建议不要这样做。
Go Go
来看看Hooks的例子,咱们先从最熟悉的开始:函数组件。
以下 OneTimeButton 是函数组件,所做的事情就是当我们点击的时候调用 sayHi
方法。
import React from 'react';
import { render } from 'react-dom';
function OneTimeButton(props) {
return (
<button onClick={props.onClick}>
点我点我
</button>
)
}
function sayHi() {
console.log('yo')
}
render(
<OneTimeButton onClick={sayHi}/>,
document.querySelector('#root')
)
我们想让这个组件做的是,跟踪它是否被点击,如果被点击了,禁用按钮,就像一次性开关一样。
但它需要一个state,因为是一个函数,它不可能有状态(React 16.8之前),所以需要重构成类。
函数组件转换为类组件的过程中大概有5个阶段:
- 否认:也许它不需要是一个类,我们可以把 state 放到其它地方。
- 实现: 废话,必须把它变成一个
class
,不是吗? - 接受:好吧,我会改的。
- 努力加班重写:首先 写
class Thing extends React.Component
,然后 实现render
等等 。 - 最后:添加state。
class OneTimeButton extends React.Component {
state = {
clicked: false
}
handleClick = () => {
this.props.onClick();
// Ok, no more clicking.
this.setState({ clicked: true });
}
render() {
return (
<button
onClick={this.handleClick}
disabled={this.state.clicked}
>
You Can Only Click Me Once
</button>
);
}
}
这是相当多的代码,组件的结构也发生了很大的变化, 我们需要多个小的功能,就需要改写很多。
使用 Hook 轻松添加 State
接下来,使用新的 useState
hook向普通函数组件添加状态:
import React, { useState } from 'react'
function OneTimeButton(props) {
const [clicked, setClicked] = useState(false)
function doClick() {
props.onClick();
setClicked(true)
}
return (
<button
onClick={clicked ? undefined : doClick}
disabled={clicked}
>
点我点我
</button>
)
}
这段代码是如何工作的
这段代码的大部分看起来像我们一分钟前写的普通函数组件,除了useState
。
useState
是一个hook。 它的名字以“use”开头(这是Hooks的规则之一 - 它们的名字必须以“use”开头)。
useState
hook 的参数是 state 的初始值,返回一个包含两个元素的数组:当前state和一个用于更改state 的函数。
类组件有一个大的state对象,一个函数this.setState
一次改变整个state对象。
函数组件根本没有状态,但useState
hook允许我们在需要时添加很小的状态块。 因此,如果只需要一个布尔值,我们就可以创建一些状态来保存它。
由于Hook
以某种特殊方式创建这些状态,并且在函数组件内也没有像setState
函数来更改状态,因此 Hook 需要一个函数来更新每个状态。 所以 useState
返回是一对对应关系:一个值,一个更新该值函数。 当然,值可以是任何东西 - 任何JS类型 - 数字,布尔值,对象,数组等。
现在,你应该有很多疑问,如:
- 当组件重新渲染时,每次都不会重新创建新的状态吗? React如何知道旧状态是什么?
- 为什么hook 名称必须以“use”开头? 这看起来很可疑。
- 如果这是一个命名规则,那是否意味着我可以自定义 Hook。
- 如何存储更复杂的状态,很多场景不单单只有一个状态值这么简单。
Hooks 的魔力
将有状态信息存储在看似无状态的函数组件中,这是一个奇怪的悖论。这是第一个关于钩子的问题,咱们必须弄清楚它们是如何工作的。
原作者得的第一个猜测是某种编译器的在背后操众。搜索代码useWhatever
并以某种方式用有状态逻辑替换它。
然后再听说了调用顺序规则(它们每次必须以相同的顺序调用),这让我更加困惑。这就是它的工作原理。
React第一次渲染函数组件时,它同时会创建一个对象与之共存,该对象是该组件实例的定制对象,而不是全局对象。只要组件存在于DOM中,这个组件的对象就会一直存在。
使用该对象,React
可以跟踪属于组件的各种元数据位。
请记住,React组件甚至函数组件都从未进行过自渲染。它们不直接返回HTML
。组件依赖于React
在适当的时候调用它们,它们返回的对象结构React
可以转换为DOM
节点。
React有能力在调用每个组件之前做一些设置,这就是它设置这个状态的时候。
其中做的一件事设置 Hooks 数组。 它开始是空的, 每次调用一个hook
时,React 都会向该数组添加该 hook
。
为什么顺序很重要
假设咱们有以下这个组件:
function AudioPlayer() {
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
.....
}
因为它调用useState
3次,React 会在第一次渲染时将这三个 hook 放入 Hooks 数组中。
下次渲染时,同样的3
个hooks
以相同的顺序被调用,所以React
可以查看它的数组,并发现已经在位置0
有一个useState
hook ,所以React
不会创建一个新状态,而是返回现有状态。
这就是React能够在多个函数调用中创建和维护状态的方式,即使变量本身每次都超出作用域。
多个useState 调用示例
让咱们更详细地看看这是如何实现的,第一次渲染:
React 创建组件时,它还没有调用函数。React 创建元数据对象和Hooks的空数组。假设这个对象有一个名为
nextHook
的属性,它被放到索引为0
的位置上,运行的第一个hook将占用位置0
。React 调用你的组件(这意味着它知道存储
hooks
的元数据对象)。调用
useState
,React创建一个新的状态,将它放在hooks
数组的第0
位,并返回[volume,setVolume]
对,并将volume
设置为其初始值80
,它还将nextHook
索引递增1。再次调用
useState
,React查看数组的第1
位,看到它是空的,并创建一个新的状态。 然后它将nextHook
索引递增为2
,并返回[position,setPosition]
。第三次调用
useState
。 React看到位置2
为空,同样创建新状态,将nextHook
递增到3
,并返回[isPlaying,setPlaying]
。
现在,hooks
数组中有3
个hook,渲染完成。 下一次渲染会发生什么?
React
需要重新渲染组件, 由于 React 之前已经看过这个组件,它已经有了元数据关联。React
将nextHook
索引重置为0
,并调用组件。- 调用
useState
,React查看索引0
处的hooks数组,并发现它已经在该槽中有一个hook。,所以无需重新创建一个,它将nextHook
推进到索引1
并返回[volume,setVolume]
,其中volume
仍设置为80
。 - 再次调用
useState
。 这次,nextHook
为1
,所以React
检查数组的索引1
。同样,hook 已经存在,所以它递增nextHook
并返回[position,setPosition]
。 - 第三次调用
useState
,我想你知道现在发生了什么。
就是这样了,知道了原理,看起来也就不那么神奇了, 但它确实依赖于一些规则,所以才有使用 Hooks 规则。
Hooks 的规则
自定义 hooks 函数只需要遵守规则 3 :它们的名称必须以“use”为前缀。
例如,我们可以从AudioPlayer
组件中将3个状态提取到自己的自定义钩子中:
function AudioPlayer() {
// Extract these 3 pieces of state:
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
// < beautiful audio player goes here >
}
因此,咱们可以创建一个专门处理这些状态的新函数,并使用一些额外的方法返回一个对象,以便更容易启动和停止播放,例如:
function usePlayerState(lengthOfClip) {
const [volume, setVolume] = useState(80);
const [position, setPosition] = useState(0);
const [isPlaying, setPlaying] = useState(false);
const stop = () => {
setPlaying(false);
setPosition(0);
}
const start = () => {
setPlaying(true);
}
return {
volume,
position,
isPlaying,
setVolume,
setPosition,
start,
stop
};
}
像这样提取状态的一个好处是可以将相关的逻辑和行为组合在一起。可以提取一组状态和相关事件处理程序以及其他更新逻辑,这不仅可以清理组件代码,还可以使这些逻辑和行为可重用。
另外,通过在自定义hooks
中调用自定义hooks
,可以将hooks
组合在一起。hooks只是函数,当然,函数可以调用其他函数。
总结
Hooks 提供了一种新的方式来处理React中的问题,其中的思想是很有意思且新奇的。
React团队整合了一组很棒的文档和一个常见问题解答,从是否需要重写所有的类组件到钩Hooks是否因为在渲染中创建函数而变慢? 以及两者之间的所有东西,所以一定要看看。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://daveceddia.com/intro-to-hooks/
关于Fundebug
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了20亿+错误事件,付费客户有阳光保险、核桃编程、荔枝FM、掌门1对1、微脉、青团社等众多品牌企业。欢迎大家免费试用!
React Hooks究竟是什么呢?的更多相关文章
- React Hooks 实现和由来以及解决的问题
与React类组件相比,React函数式组件究竟有何不同? 一般的回答都是: 类组件比函数式组件多了更多的特性,比如 state,那如果有 Hooks 之后呢? 函数组件性能比类组件好,但是在现代浏览 ...
- 蒲公英 · JELLY技术周刊 Vol.21 -- 技术周刊 · React Hooks vs Vue 3 + Composition API
蒲公英 · JELLY技术周刊 Vol.21 选 React 还是 Vue,每个人心中都会有自己的答案,有很多理由去 pick 心水的框架,但是当我们扪心自问,我们真的可以公正的来评价这两者之间的差异 ...
- 你真的会用react hooks?看看eslint警告吧!(如何发请求、提升代码性能等问题)
前言 看过几个react hooks 的项目,控制台上几百条警告,大多是语法不规范,react hooks 使用有风险,也有项目直接没开eslint.当然,这些项目肯定跑起来了,因为react自身或者 ...
- 通过 React Hooks 声明式地使用 setInterval
本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: setInterval 用起来没你想的简单. Ryan Florence 在他 ...
- 初探React Hooks & SSR改造
Hooks React v16.8 发布了 Hooks,其主要是解决跨组件.组件复用的状态管理问题. 在 class 中组件的状态封装在对象中,然后通过单向数据流来组织组件间的状态交互.这种模式下,跨 ...
- React hooks实践
前言 最近要对旧的项目进行重构,统一使用全新的react技术栈.同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function c ...
- 理解 React Hooks
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由志航发表于云+社区专栏 TL;DR 一句话总结 React Hooks 就是在 react 函数组件中,也可以使用类组件(classe ...
- React Hooks新特性学习随笔
React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...
- 关于React Hooks,你不得不知的事
React Hooks是React 16.8发布以来最吸引人的特性之一.在开始介绍React Hooks之前,让咱们先来理解一下什么是hooks.wikipedia是这样给hook下定义的: In c ...
随机推荐
- Initialize a Property After Creating an Object 创建对象后初始化属性 (XPO)
In this lesson, you will learn how to set the default value for a particular property of a business ...
- Fundebug前端异常监控插件更新至2.0.0,全面支持TypeScript
摘要: 是时候支持TS了! Fundebug前端异常监控服务 Fundebug提供专业的前端异常监控服务,我们的插件可以提供全方位的异常监控,可以帮助开发者第一时间定位各种前端异常,包括但不限于Jav ...
- 如何通过RMAN使用传输表空间迁移到不同的Endian平台 (Doc ID 371556.1)
How to Migrate to different Endian Platform Using Transportable Tablespaces With RMAN (Doc ID 371556 ...
- Linux Ctrl + Alt + Fx | (x = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
VMware Ubuntu中,按下 Ctrl + Alt + Fx | (x = 1...12),会出现不同的效果. 1. Ctrl + Alt + F1 ~ F6 Ctrl + Alt + F1 ~ ...
- @ConfigurationProperties(pref="")加载局部配置文件
刚开始@ConfigurationProperties(文件名)直接在参数里加文件名,其实是配置前缀pref="前缀".加载局部配置文件是@PropertySource(value ...
- 算法问题实战策略 SORTGAME
地址 https://algospot.com/judge/problem/read/SORTGAME 解答 常规BFS是会超时的 按照书上的提示 应该是打表(居然还有提倡打表的题目) tle 代码 ...
- 第05组 Alpha冲刺(3/4)
第05组 Alpha冲刺(3/4) 队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了 ...
- Luogu P5298 [PKUWC2018]Minimax
好劲的题目啊,根本没往线段树合并方面去想啊 首先每种权值都有可能出现,因此我们先排个序然后一个一个求概率 由于此时数的值域变成\([1,m]\)(离散以后),我们可以设一个DP:\(f_{x,i}\) ...
- Python连载47-json文件、正则表达式初步
一.在线工具 1.https://www.sojson.com/ 2.http://www.w3cshool.com.cn/json/ 3.http://www.runoob.com/json/jso ...
- Spring 中AOP及前后置增强案例
1.AOP面向切面编程 面向切面编程的本质:面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来. 1主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等. 2主要意 ...