React 系列 之 React Hooks(一) JSX本质、理解Hooks

借鉴自极客时间《React Hooks 核心原理与实战》

JSX语法的本质

可以认为JSX是一种语法糖,允许将html和js代码进行结合。
JSX文件会通过babel编译成js文件
下面有一段JSX代码,实现了一个Counter组件

import React from "react";

export default function Counter() {
  const [count, setCount] = React.useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>{count}</button>
    </div>
  );
}

这段代码也可以形成js:

React.createElement(
  "div",
  null,
  React.createElement(
    "button",
    { onClick: function onClick() {
        return setCount(count + 1);
      } },
    React.createElement(CountLabel, { count: count })
  )
);

用到了React的一个api:React.createElement,它的作用是创建组件的实例。这个api的参数:

  • 第一个参数:组件类型,内置组件(对应于html元素)为小写,自定义组件为大写驼峰
  • 第二个参数:为组件添加的属性,即props
  • 第三个及以后的参数:该组件的children

所以呢,通过 createElement 这个 API,我们可以构建出需要的组件树,而 JSX 只是让这种描述变得更加直观和高效。
因此,JSX 不是一个新的概念,而只是原生 JavaScript 的另一种写法。但是换成这种写法,会大大降低你上手 React 的难度。

React组件的本质

从model(state+props)到 view的映射
在这里插入图片描述
React 会帮助你处理所有 DOM 变化的细节。而且,当 Model 中的状态发生变化时,UI 会自动变化,即所谓的数据绑定。
把UI的展现看做是函数的执行

f(变化的model)  => 新的dom树,然后把新的dom树以最优的方法更新到浏览器

为什么要发明 Hooks?

Class组件,有不适合的地方,浪费了类的两个特点:1. 不需要人为调用Class实例的方法,这个Class的特点就浪费了 2. React的类之间没有继承,这个特点也浪费了。
函数组件,也有不合适的地方,1. 没有自己的生命周期,2. 函数自身无法记录状态

我们想要强化函数组件,让它能有状态,让它关联到一个存储在外部的状态,那么Hooks的思想就诞生了

把一个外部的数据绑定到(钩到)函数的执行。
当被钩到的数据或事件发生变化时,产生这个目标结果的代码会重新执行,产生更新后的结果。
对于函数组件,这个结果是最终的 DOM 树

有一点需要特别注意,Hooks 中被钩的对象,不仅可以是某个独立的数据源,也可以是另一个 Hook 执行的结果,这就带来了 Hooks 的最大好处:逻辑的复用。

hooks的过人之处

1 逻辑复用

或者说是简化了逻辑复用
以往的一些逻辑复用,需要借助高阶组件来完成(这是一个复杂的设计模式),但是hooks就能简化这一过程。
举个例子: 调整窗口大小
a. 高阶组件方法
高阶组件实现思路:高阶组件负责监听窗口大小变化,并将变化后的值作为 props 传给下一个组件。

// 组件为参数,最后返回一个包装过的组件
const withWindowSize = Component => {
	// 产生一个高阶组件 WrappedComponent,只包含监听窗口大小的逻辑
	class WrappedComponent extends React.PureComponent {
		constructor(props) {
			super(props);
			this.state = {
			  size: this.getSize() 
			};
		}
		// 组件生命周期对应状态 挂到window的listener上
		componentDidMount() {
		    window.addEventListener("resize", this.handleResize);
		}
		componentWillUnmount() {
			window.removeEventListener("resize", this.handleResize);
		}
		// 获取当前window的size
		getSize() {
			return window.innerWidth > 1000 ? "large" : "small";
		}
		handleResize = () => {
			const currentSize = this.getSize();
			this.setState({
				size: this.getSize()
			});
		}
		render() {
		    // 将窗口大小传递给真正的业务逻辑组件
			return <Component size={this.state.size} />
		}
	}
	return WrappedComponent;
};

然后在自定义组件中调用withWindowSize 这样的函数来产生一个新组件,并自带size属性,例如:

class MyComponent extends React.Component {
	render() {
		const {size} = this.props;
		if(size === 'small') return <SmallComponent />;
		else return <LargeComponent />;
	}
}
// 使用 withWindowSize 产生高阶组件,用于产生 size 属性传递给真正的业务组件
export default withWindowSize(MyComponent)

因为size是props中得到的,即是从父组件传递下来的,所以当WrappedComponent组件中监听到窗口变化时,会更新size的值,从而会让MyComponent重新渲染

高阶组件的缺点:

  1. 代码难理解,不直观,很多人甚至宁愿重复代码,也不愿用高阶组件;
  2. 增加额外的组件节点。每一个高阶组件都会多一层节点,这就会给调试带来很大的负担。

那么用hooks如何实现?
b. hooks方法


const useWindowSize = () => {
  const [size, setSize] = useState(getSize());
  useEffect(() => {
    const handler = () => { setSize(getSize()); }
    window.addEventListener('resize', handler);
    // 回调函数可以返回一个清理函数。这个清理函数在组件卸载时或者在下一次 effect 执行之前执行,
    return () => {
      window.removeEventListener('resize', handler);
    };
  }, []);  // 空的依赖项数组意味着此效果只会运行一次,类似于类组件中的 componentDidMount
  return size;
}

在组件中使用useWindowSize

const Demo = () => {
  const size = useWindowSize();
  if (size == 'small') return <SmallComponent />;
  else return <LargeComponent />;
}

窗口大小是一个外部的数据状态,但我们通过Hooks的方式对其进行了封装,将其变成一个可绑定的数据源。每当窗口大小发生变化时,使用这个Hook的组件就会重新渲染。(当窗口大小改变时,注册的事件监听器会触发,并调用 handler 函数,该函数会更新 size 状态的值。在 Demo 组件中,根据 size 的值来决定渲染 SmallComponent 还是 LargeComponent。当 size 的值在窗口大小变化时被更新后,会触发组件的重新渲染,因为组件的渲染取决于 size 的值)

2 有助于关注分离

Hooks能够将针对同一个业务逻辑的代码尽可能聚合在一块儿,让代码更容易理解和维护,相比之下,Class组件无法做到这一点,因为Class组件中,不得不把同一个业务逻辑的代码分散在类组件的不同生命周期方法中。
举个例子:上面的窗口大小变化监听代码
Class组件中,我们在componentDidMountcomponentWillUnmount中分别去监听事件和解绑事件;
而在函数组件中,就可以把逻辑都集中写在hooks里

Hooks所解决的问题是什么?

  1. 更好地体现了React的开发思想,即 State => View 的函数式映射
  2. 更好地解决了 Class 组件存在的一些代码冗余、难以逻辑复用的问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/476590.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java代码基础算法练习-求一个三位数的各位平方之和-2024.03.21

任务描述&#xff1a; 输入一个正整数n&#xff08;取值范围&#xff1a;100<n<1000&#xff09;&#xff0c;然后输出每位数字的平方和。 任务要求&#xff1a; 代码示例&#xff1a; package march0317_0331;import java.util.Scanner;public class m240321 {public …

java.lang.String final

关于String不可变的问题&#xff1a;从毕业面试到现在&#xff0c;一个群里讨论的东西&#xff0c;反正码农面试啥都有&#xff0c;这也是我不咋喜欢面试代码&#xff0c;因为对于我而言&#xff0c;我并不喜欢这些面试。知道或不知道基本没啥含氧量&#xff0c;就是看看源代码…

程序员为什么宁愿失业都不愿意搭伙去接单?

我要说一个关键词&#xff1a;信息差&#xff0c;这个词将贯彻这整篇文章。 大多数程序员觉得&#xff0c;接单不稳定、金额低、单子少&#xff0c;又卷又没有性价比。从某种角度上说&#xff0c;这个说法也没错&#xff0c;但作为业余接单者&#xff0c;本就不应该把接单当做主…

【Java常用API】简单爬虫练习题

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

【Unity实战系列】Unity的下载安装以及汉化教程

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;怎么说呢&#xff0c;其实这才是我以后真正想写想做的东西&#xff0c;虽然才刚开始&#xff0c;但好歹&#xff0c;我总算是启程了。今天要分享…

Java特性之设计模式【装饰器模式】

一、装饰器模式 概述 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种类型的设计模式属于结构型模式&#xff0c;它是作为现有的类的一个包装 装饰器模式通过将对象包装在装饰器类中&#xff0c;以…

单片机--数电(4)

触发器 数字电路中&#xff1a;分组合逻辑电路与时序逻辑电路两大类 组合逻辑电路的基本单元是门电路&#xff08;与或非等一些门电路&#xff09; 时序逻辑电路的基本单元是触发器 触发器与门电路的区别 门电路某一时刻的输出信号完全取决于该时刻的输入信号&#xff0c;…

【目标检测实验系列】AutoDL线上GPU服务器租用流程以及如何用Pycharm软件远程连接服务器进行模型训练 (以Pycharm远程训练Yolov5项目为例子 超详细)

目录 1. 文章主要内容2. 租用AutoDL服务器详细教程2.1 注册AutoDL账号&#xff0c;并申请学生认证(学生认证有优惠&#xff0c;如果不是学生可以忽略此点)2.2 算力市场选择GPU&#xff0c;并选择初始化配置环境2.3 控制台参数解析&#xff0c;并使用相关参数登录Xftp(Windows与…

安卓开发日记:实现APP重启逻辑,适用于热更后重启游戏进行加载

可根据合适的弹窗搭配使用重启逻辑&#xff0c;建议使用在热更包加载后使用&#xff0c;帮助部分热更后未及时生效的逻辑范围首先&#xff0c;在逻辑调用Activity类中创建一个成员变量&#xff0c;给后续逻辑接口直接使用 如下 public class MainActivity extends Activity {…

rundeck k8s部署踩坑

1、镜像启动后原来的定时任务无法运行 参考&#xff1a; https://github.com/rundeck/rundeck/issues/4275 https://stackoverflow.com/questions/60942785/env-variable-for-rundeck-feature-joblifecycleplugin-enabled/60959605#60959605 结论&#xff1a; &#xff08;1&…

vue3项目中使用 hiprint

基于 vue3 的打印 hiprint 打印官网 hiprint hiprint 是一个web 打印的js组件&#xff0c;无需安装软件。支持移动端&#xff0c;PC端浏览器&#xff0c;angular,vue,react, 等 分页预览&#xff0c;打印&#xff0c;操作简单&#xff0c;运行快速。 在 vue3 项目中使用打印&a…

【嵌入式学习】Qtday03.21

一、思维导图 二、练习 自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面。&#xff08;不要使用课堂上的图片和代码&#xff0c;自己发挥&#xff0c;有利于后面项目的完成&#xff09; 要求&#xff1a; 1. 需要使用Ui界面文件进行界面设计 2. ui界面上的组件…

shell脚本命令

最后更新日期&#xff1a;2024-03-21 文章目录 一、echo二、特殊变量1、$n2、$#3、$*4、$5、$? 三、运算符1、expr2、$[nn] 三、条件判断1、[ condition ]2、&&3、|| 四、流程控制1、if2、case3、for4、while 五、read读取控制台输入 一、echo 打印变量 #! /bin/ba…

k8s安装详细教程1

环境初始化 1、检查操作系统的版本 Last login: Mon Mar 18 08:57:10 2024 [rootcontroller ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootcontroller ~]# vi /etc/hosts2、时间同步 kubernetes要求集群中的节点时间必须精确一直&#xff0c;这里…

32.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-网络数据分析原理与依据

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;31.其它消息的实…

除了Confluence,有没有其他工具一样好用?

每个团队都需要一个协同工作工具&#xff0c;以更有效地管理任务、跟踪进度和分享知识。这就是Atlassian的Confluence发挥作用的地方。然而&#xff0c;尽管它相当强大&#xff0c;其昂贵的价格和复杂的界面可能会让某些用户望而却步。所以&#xff0c;还有其他工具可以替代Con…

Markdown快速入门(常用技巧)

目录 说明常用书写技巧1.标题分级2.代码块3.字体4.引用语法5.分割线6.图片插入(本地/网络&#xff09;7.超链接8.列表9.表格10.换行&#xff08;两个空格&#xff09;11.插入公式12.脚注 说明 markdown实际上类似于网页&#xff0c;可以根据喜欢设置其样式变化&#xff0c;创建…

多模态开源大模型

感知类总榜单&#xff0c;是将各项感知任务综合起来的总评分&#xff0c;显示是BLIP-2最高&#xff1a; 认知类总榜单&#xff0c;则是各种涉及认知类任务的榜单&#xff0c;加起来是MiniGPT-4最高&#xff1a; 一、LLaVA-1.5&#xff08;浙大实验室》&#xff1a;LLaVA 二、…

如何修复WordPress网站媒体库上传文件失败的问题

公司最近推出了一系列新产品&#xff0c;为了更新网站的视频和图片&#xff0c;我们需要将它们上传至网站媒体库。然而&#xff0c;在上传视频时&#xff0c;我们却遇到了一些问题。系统提示说&#xff0c;我们尝试上传的视频文件大小超出了站点的最大上传限制。尽管我们的视频…

实战whisper第二天:直播语音转字幕(全部代码和详细部署步骤)

直播语音实时转字幕&#xff1a; 基于Whisper的实时直播语音转录或翻译是一项使用OpenAI的Whisper模型实现的技术&#xff0c;它能够实时将直播中的语音内容转录成文本&#xff0c;甚至翻译成另一种语言。这一过程大致分为三个步骤&#xff1a;捕获直播音频流、语音识别&#x…