React hooks文档笔记(二) 添加交互性

添加交互性

  • 1. 事件传播
    • 1.1 停止传播
    • 1.2 阻止默认事件
  • 2. [Hook] useState 状态
  • 3. 渲染和提交
    • 3.1 触发渲染
    • 3.2 React渲染组件
    • 3.3 提交对 DOM 的更改
    • 3.4 浏览器绘制
  • 4. 渲染快照
    • 状态队列例子
  • 5. 更新state中的对象

1. 事件传播

js的事件流:

  • 事件捕获:从外到内
  • 事件冒泡:从内到外(默认模式)
export default function Toolbar() {return (<div className="Toolbar" onClick={() => {alert('You clicked on the toolbar!');}}><button onClick={() => alert('Playing!')}>Play Movie</button><button onClick={() => alert('Uploading!')}>Upload Image</button></div>);
}

点击任一按钮,它的 onClick 将首先运行,然后是父节点

的 onClick—— 所以会出现两条消息。
在这里插入图片描述
在这里插入图片描述 在这里插入图片描述如果你点击灰色区域本身,只有父
的 onClick 会运行。

1.1 停止传播

为阻止传播,可以在onClick中加一行引用事件参数e并调用e.stopPropagation()方法,此时当用户点击<button>时触发器该条语句,停止事件向外扩散,父节点<div>的onClick将不再触发。

1.2 阻止默认事件

e.preventDefault() 阻止默认行为
<form>:当内部按钮点击后,将默认重载整个页面

export default function Signup() {return (<form onSubmit={e => {e.preventDefault();    //点击按钮后将不再重载页面alert('Submitting!');}}><input /><button>Send</button></form>);
}

2. [Hook] useState 状态

形式:const [index, setIndex] = useState(默认值)

“[]”从useState解构出来两部分,

  1. 用于保留渲染之间数据的状态变量index
  2. 一个状态设置函数,setIndex用于更新变量触发 React 再次渲染组件

只能使用在组件,不能在条件、循环或其他嵌套函数中调用 Hooks,hook调用原理:
React报错#310复盘小结+hooks使用的场景+调用原理

只有 Hook 的调用顺序在多次渲染之间保持一致,React 才能正确地将内部 state 和对应的 Hook 进行关联。

useState内部:

React 为每个组件保存一组状态对。 它还维护当前对索引,该索引在渲染前设置为 0。 每次调用 useState 时,React 都会为您提供下一个状态对并递增索引。

let componentHooks = [];
let currentHookIndex = 0;
// How useState works inside React (simplified).
function useState(initialState) {let pair = componentHooks[currentHookIndex];if (pair) {// This is not the first render,// so the state pair already exists.// Return it and prepare for next Hook call.currentHookIndex++;return pair;}// This is the first time we're rendering,// so create a state pair and store it.pair = [initialState, setState];function setState(nextState) {// When the user requests a state change,// put the new value into the pair.pair[0] = nextState;updateDOM();}// Store the pair for future renders// and prepare for the next Hook call.componentHooks[currentHookIndex] = pair;currentHookIndex++;return pair;
}

3. 渲染和提交

举个例子:

组件是厨房里的厨师,用食材烹制美味佳肴。React 是一个服务员,负责接收客户的订单并为他们带来菜肴。这个请求和提供 UI 的过程分为三个步骤:

  1. 触发渲染(将客人的订单送到厨房)
  2. 渲染组件(在厨房准备订单)
  3. 提交给 DOM(将制作好的菜肴放在客户的桌上)
    在这里插入图片描述

3.1 触发渲染

组件渲染有两个原因:

  1. 初始渲染
    root.render(<App />);

  2. 组件(或其祖先之一)的state已更新

3.2 React渲染组件

export default function Gallery() {return (<section><h1>Inspiring Sculptures</h1><Image /><Image /></section>);
}
function Image() {return (<img src="xxx" alt="xxx" />);
}
  • 在初始渲染时,React 将调用根组件。
    <section><h1> 和两个<img>标签创建DOM节点

  • 对于后续的渲染,React 将调用状态更新触发渲染的函数组件
    React 将计算它们的哪些属性(如果有)自上次渲染以来发生了变化。 在下一步,即提交阶段之前,它不会对这些信息做任何事情。

3.3 提交对 DOM 的更改

  • 初始渲染时,React 将使用appendChild() DOM API 将它创建的所有 DOM 节点放在屏幕上。
  • 对于重新渲染,React 将应用最少的必要操作(在渲染时计算!)以使 DOM 匹配最新的渲染输出。

如果渲染之间存在差异,React 只会更改 DOM 节点。

举例:
Clock组件会随着父节点传入不同的props 参数 time 而重新渲染,但在input中输入‘1’,重新渲染时‘1’没有消失。

export default function Clock({ time }) {return (<><h1>{time}</h1><input /></>);
}

在这里插入图片描述在这里插入图片描述

这是因为随着time的改变, React 只更新了<h1>的内容,而没有触及<input>

3.4 浏览器绘制

渲染完成并且 React 更新 DOM 后,浏览器将重新绘制屏幕

4. 渲染快照

当 React 重新渲染一个组件时:

  1. React 再次调用你的函数。
  2. 您的函数返回一个新的 JSX 快照(使用该渲染中的state计算的,在快照中保持状态值“固定”)
  3. React 然后更新屏幕以匹配您返回的快照。

在这里插入图片描述
setState 只会为下一次渲染更改它

export default function Counter() {const [number, setNumber] = useState(0);return (<><h1>{number}</h1><button onClick={() => {setNumber(number + 1);setNumber(number + 1);}}>+2</button></>)
}

点击第一次后:
在这里插入图片描述
点击第二次后:
在这里插入图片描述
发现两次点击都只加了1

在第一次渲染期间,number是0,调用onClick:
第一个setNumber(number + 1)等价于 setNumber(0 + 1)
第二个setNumber(number + 1)等价于 setNumber(0 + 1)
React 准备在下一次渲染时更改number为1,也就是说设置状态为1了两次
在这里插入图片描述

在处理状态更新之前,React 会等到事件处理程序中的所有代码都已运行。这使您可以更新多个状态变量——甚至来自多个组件——而不会触发太多重新渲染

q: 在下一次渲染之前需要多次更新相同的state?


答: 可以传递一个函数,该函数根据前一个状态计算下一个状态队列
例如将上述例子替换为setNumber(n => n + 1);

n => n + 1更新函数(必须是纯函数并且只返回结果)

当您将它传递给状态设置器时:

  1. 在事件处理程序中的所有其他代码运行之后,React 将此函数排队等待处理。
  2. 在下一次渲染期间,React 遍历队列并为您提供最终的更新状态。
队列更新nreturns
n => n + 100+1=1
n => n + 111+1=2

状态队列例子

实现状态队列:https://codesandbox.io/s/0xym3z?file=/processQueue.js&utm_medium=sandpack

<button onClick={() => {setNumber(number + 5);setNumber(n => n + 1);setNumber(42);
}}>
队列更新nreturns
“replace with 5”0(unused)5
n => n + 155+1=6
“replace with 42”6(unused) 42

在下一次渲染期间,React 遍历状态队列:

  1. setNumber(number + 5): number是0,所以setNumber(0 + 5)。React 将“替换为5”添加到它的队列中。
  2. setNumber(n => n + 1): n => n + 1是一个更新函数。React 将该函数添加到它的队列中。
  3. setNumber(42): React 将“替换为42”添加到它的队列中。

5. 更新state中的对象

用 Immer 编写简洁的更新对象state逻辑:Immer编写简洁的更新state逻辑

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【DBA课程-笔记】MongoDB入门到云上开发

课程目的&#xff1a;成为专业MongoDB的DBA nosql第一&#xff1a;MongoDB 一、讲师&#xff1a; 二、课程目录 第1章&#xff1a;MongoDB数据库入门 第2章&#xff1a;MongoDB数据数据查询与分析 第3章&#xff1a;MongoDB数据库核心知识 第4章&#xff1a;MongoDB数据库管…

MySQL索引

文章目录 MySQL索引1 索引1.1 索引的概念1.2 索引的作用1.3 创建索引的原则依据 2 索引的分类和创建2.1 普通索引2.1.1 直接创建索引2.1.2 修改表方式创建2.1.3 创建表的时候指定索引 2.2 唯一索引2.2.1 直接创建唯一索引2.2.2 修改表方式创建唯一索引2.2.3 创建表的时候指定唯…

SQlite3 编译

参考博客&#xff1a;https://blog.csdn.net/flowerspring/article/details/121268403 1.下载C源码以及def文件https://www.sqlite.org/download.html 2. 下载完成之后解压 sqlite-amalgamation获取C源码&#xff0c;解压sqlite-dll-win32-xx获取里面的def文件。 3.新建sqlite…

MySQL的面试题讲解看完肯定对你有帮助!!

一、理论方面 1.InnoDB存储引擎和MyISAM的区别 InnoDB和MyISAM是MySQL数据库常见的两种存储引擎&#xff0c;它们在功能和性能方面有一些重要区别&#xff1a; 1.事务支持&#xff1a;InnoDB是一个支持事务处理的存储引擎&#xff0c;它使用了ACID&#xff08;原子性、一致性、…

SciencePub学术 | 数据处理类重点SCIEEI征稿中

SciencePub学术 刊源推荐: 数据处理类重点SCI&EI征稿中&#xff01;信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 数据处理类重点SCIE&EI 【期刊简介】IF&#xff1a;3.5-4.0&#xff0c;JCR2区&#xff0c;中科院4区&#xff1b; 【出版社】…

SpringBoot+WebSocket+Session共享

前言 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端 一、为什么需要WebSocket HTTP 是基于请求响应式的&#xff0c;即通信只能由客户端发起&#xff0c;服务端做出响应&#xff0c;无状态&…

kafka入门,节点服役和退役(新增节点和删除节点)(十二)

1、节点服役 1、克隆准备其中一台节点 2、如果新节点的kafka有被log和datas文件夹要删除 3、修改/etc/hosts 配置新节点映射 1.1 执行负载均衡操作 vim topics-to-move.json{"topic": "主题名称"} {"topics": [{"topic": "fi…

web测试需要注意几个非常重要的测试点

微软语言标准&#xff1a; 全角字符和半角字符都要使用一个空格分开 英文和数字直接要有空页面分辨率&#xff1a; 通常是计算机的默认分辨率&#xff0c;但是还是会有一些老式电脑存在1024*768的情况 浏览器的兼容性&#xff1a; 目前市场上的主流浏览器&#xff1a;IE8.0-…

如何在Mac终端上,用十六进制查看某个硬盘(使用dd和hexdump,所以其他系统也可以使用这个方法)

首先需要强调&#xff1a;这种方法不能保证所有的硬盘都可以查看&#xff0c;有些硬盘由于一些原因会显示“Resource busy”&#xff0c;比如说时间机器的硬盘&#xff0c;内置硬盘等。 准备&#xff1a; 当然是一台 Mac&#xff1b;hexdump程序dd程序 方法如下&#xff1a;…

QT或VS2015报错:Error: C2661: QColor::ct::ct: 没有重载函数接受 5 个参数解决方案

安装了QT5.14.2 MSCV2015配置并同时在QT或VS2015测试并运行都提示没有重载函数接受 5 个参数。 同时还会出现C2134错误&#xff1a;QMetaObject::SuperData::operator const QMetaObject *: 调用不会生成常数表达式的错误 搜索了网络上的结果都让换其它版本&#xff0c;没有…

【Telephony】SIM单卡到双卡的变化

1、注册观察者 --> PhoneFactory.makeDefaultPhones() --> TelephonyComponentFactory.makeSubscriptionInfoUpdater() --> new SubscriptionInfoUpdater() --> PhoneConfigurationManager.registerForMultiSimConfigChange(this, EVENT_MULTI_SIM_CONFIG_CHAN…

06、Nginx反向代理与负载均衡

反向代理&#xff1a; 这种代理方式叫做&#xff0c;隧道代理。有性能瓶颈&#xff0c;因为所有的数据都经过Nginx&#xff0c;所以Nginx服务器的性能至关重要 负载均衡&#xff1a; 把请求&#xff0c;按照一定算法规则&#xff0c;分配给多台业务服务器&#xff08;即使其中…