React+TS 从零开始教程(4):useEffect
上一节传送门:React+TS 从零开始教程(3):useState
源码链接:https://pan.quark.cn/s/c6fbc31dcb02
上一节,我们已经学会了React的第一个Hook:useState。 这一节,我们要学习的是另一个非常重要的Hook:useEffect。 Effect在这里,意为副作用? 不论是哪一个Hook,都是写在函数里面的,比如上个章节中useEffect,就是写在一个函数中。
import React, { useState } from "react";const Switch = () => {//每一个变量都要单独做一个State//useState解构出两个变量,一个是变量名,一个是赋值这个变量的函数const [on,setOn] = useState(false)return (<><h2 onClick={ () => {setOn(!on)}}>{on?'关闭':'开启'}</h2></>)
}export default Switch;
所以,这个副作用,就是函数的副作用。 怎么理解呢?我们知道,函数就是你给我参数,我给你一个确定的返回,这个叫函数。但是呢,有一些操作其实跟函数的返回没有太大的关系,却出现在了函数体中,比如网络请求,订阅事件等,这些跟函数渲染不相关,就可以被认为是副作用。
两种常见的副作用。
不需要清除的副作用
我们希望在React更新DOM之后,发送一些网络请求,手动变更DOM,记录日志等,这些操作在我们函数返回之后,完全可以忽略掉。 这些情形,就是不需要清除的副作用。 总之,当React函数式组件return了一个DOM,并成功在页面更新之后,如果你还想做一些快活的事情,就写在useEffect的第一个回调参数里。 在Switch.tsx中,写上如下代码
//以下的effect操作会在DOM更新之后发生
useEffect(() => {document.title = 'DOM更新完毕,Effect发生!'
});
useEffect接收一个回调函数,里面定义了DOM更新完成之后的操作,或者说给组件添加了一个渲染后的副作用。 App.tsx

刷新页面

页面的标题发生了变化,符合预期。 注意,useEffect会在每次渲染后都执行1次。 之前用Class组件的时候,分挂载和更新两个钩子,所以我们想用这种DOM更新后的操作的话,就得在这两个钩子中各写一遍逻辑,很麻烦。 现在有了useEffect,就化繁为简了。 而且,非常好懂。
需要清除的副作用
有些副作用是需要被清除的,比如事件的添加。 在 之前做法中,我们是在componentDitMount中添加事件,然后在componentWillUnmount中解绑事件。 现在我们用useEffect,该如何实现呢? 我们新创建一个组件,叫MouseTracker。

顾名思义,就是一个鼠标位置的追踪器。 然后,引入React依赖
import React, { useEffect, useState } from "react";
声明一下函数组件
const MouseTracker : React.FC = () => {}
然后定义坐标状态
//定义坐标const [pos,setPos] = useState({x:0,y:0})
直接return
return (<p>X: {pos.x} , Y:{pos.y}</p>
)
导出去
export default MouseTracker;
然后在App.tsx中引入这个组件

目前这个x和y还是静态的,都是0,我们希望每次鼠标点击的时候,就更新这个坐标。 什么时候更新呢,首先是鼠标点击之后,然后触发x和y的更新,也就是dom的更新。 让我们在MouseTracker中添加一个effect
//事件绑定
useEffect(() => {const bindCallback = (e:MouseEvent) => {console.log('鼠标点击了')setPos({x:e.clientX,y:e.clientY}) }//绑定click事件document.addEventListener('click',bindCallback)
})
现在页面是这样的

我点一次

再点一次

再点一次

每次点击,都会增加N的effect次数。为什么呢?因为useEffect会在每次dom更新后触发,而我们添加了点击事件后没有及时地去清除,所以之前的点击事件还存在,导致每次更新后,所有的点击事件都触发了effect。 怎么解决呢? 我们看下useEffect的源码
/*** Accepts a function that contains imperative, possibly effectful code.** @param effect Imperative function that can return a cleanup function* @param deps If present, effect will only activate if the values in the list change.** @version 16.8.0* @see {@link https://react.dev/reference/react/useEffect}*/function useEffect(effect: EffectCallback, deps?: DependencyList): void;
可以看到,这个函数的第一个参数,callback,并不是一定为void,也允许我们返回一个函数。 @param effect Imperative function that can return a cleanup function 意思很明确了,它允许我们返回一个cleanup function,也就是清除函数。 我们修改一下代码
//事件绑定
useEffect(() => {const bindCallback = (e:MouseEvent) => {console.log('鼠标事件绑定')setPos({x:e.clientX,y:e.clientY}) }//绑定click事件document.addEventListener('click',bindCallback)return () => {document.removeEventListener('click',bindCallback)}
})
我连续点击了四次,符合预期。

怎么限制Effect
上面的例子告诉我们,只有一重新渲染,effect必执行,这可能会带来一些性能问题,有什么办法对effect做限制嘛? 再来看源码
/*** Accepts a function that contains imperative, possibly effectful code.** @param effect Imperative function that can return a cleanup function* @param deps If present, effect will only activate if the values in the list change.** @version 16.8.0* @see {@link https://react.dev/reference/react/useEffect}*/function useEffect(effect: EffectCallback, deps?: DependencyList): void;
这次我们重点看第二个参数 @param deps If present, effect will only activate if the values in the list change. 第二个参数是一个数组,如果数组里面的任何一项发生变化,就会触发effect的执行。 刚才的例子中,我们每次点击鼠标,就会触发一次事件的绑定和卸载,实在是有点太浪费了。 我们希望在组件加载的时候绑定一次就行了,然后在组件卸载的时候再解绑。
useEffect(() => {console.log('点击事件绑定')const bindCallback = (e:MouseEvent) => {console.log('鼠标点击了')setPos({x:e.clientX,y:e.clientY}) }//绑定click事件document.addEventListener('click',bindCallback)return () => {console.log('点击事件解绑')document.removeEventListener('click',bindCallback)}
},[])
我添加一个空数组,代表这个effect不依赖于任何state和props,只跟组件的安装和卸载有关。 然后修改App.tsx(省略页面其他代码)
import React,{useState} from "react";
import MouseTracker from "./components/MouseTracker";function App() {let [showMouseTracker,setShowMouseTracker] = useState(true)return (<div className="App"><div><button onClick={() => {setShowMouseTracker(!showMouseTracker)}}>{showMouseTracker ? '关闭鼠标追踪': '打开鼠标追踪'}</button></div>{showMouseTracker && <MouseTracker />}</div>);
}export default App;
刷新页面

多点几次

点击关闭按钮

页面卸载,事件解绑了。 如果你希望这个effect只依赖某一个State,将对应的变量填入这个数组即可,有多个就填多个。
本节,我们学会了useEffect的用法。
相关文章:
React+TS 从零开始教程(4):useEffect
上一节传送门:ReactTS 从零开始教程(3):useState 源码链接:https://pan.quark.cn/s/c6fbc31dcb02 上一节,我们已经学会了React的第一个Hook:useState。 这一节,我们要学习的是另一…...
网络安全学习路线图(2024版详解)
近期,大家在网上对于网络安全讨论比较多,想要学习的人也不少,但是需要学习哪些内容,按照什么顺序去学习呢?其实我们已经出国多版本的网络安全学习路线图,一直以来效果也比较不错,本次我们针对市…...
你了解人工智能吗?
前言 人工智能(Artificial Intelligence,AI)是计算机科学的一个重要分支,致力于开发能够执行通常需要人类智能的任务的系统。本文将从历史发展、关键技术、应用领域以及未来挑战等方面,深入探讨人工智能的相关内容。 …...
如何使用Vue.js实现动态文档生成与下载功能
在现代Web应用开发中,用户往往需要在浏览器端完成复杂的操作,如生成和下载特定格式的文档,而无需服务器直接干预。本文将以一个Vue.js应用程序为例,详细介绍如何利用axios(或自定义请求模块)结合FileReader…...
web基础及http协议
一、WEB:就是我们所说的页面,点开的每个页面都是web。(全球广域网、万维网) 分布式图形信息系统:同一个服务,但是部署在不同的机器上且提供的服务和内容全部一致,集群就是建立在分布式的基础上。…...
【vuejs】vue-router 之 addRoute 动态路由的应用总结
1. Vue Router 概述 Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用。它与 Vue.js 深度集成,让开发者能够轻松地构建具有复杂用户界面的单页面应用。Vue Router 允许你定义不同的路由,并通过 router-view 组件在应用中显示匹配的…...
LeetCode 30. 串联所有单词的子串
LeetCode 30. 串联所有单词的子串 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如,如果 words [“ab”,“cd”,“ef”], 那么 “abcd…...
python本学期所有代码!
第一单元 ----------------------------------------------------------------------- #圆面积的计算 radius 25 area 3.1415 * radius * radius print(area) print("{:.2f}".format(area)) --------------------------------------------------------------------…...
武汉星起航:无锡跨境电商加速“出海”,物流升级助品牌全球布局
随着全球化的不断深入,跨境电商作为数字外贸的新业态,正逐渐成为无锡企业拓展海外市场的重要渠道。武汉星起航关注到,近年来,无锡市通过积极推进国际物流枢纽建设,完善海外仓布局,以及各特色产业带的积极参…...
Python+Pytest+Allure+Yaml+Pymysql+Jenkins+GitLab接口自动化测试框架详解
PythonPytestAllureYaml接口自动化测试框架详解 编撰人:CesareCheung 更新时间:2024.06.20 一、技术栈 PythonPytestAllureYamlJenkinsGitLab 版本要求:Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 安装python3.7&…...
stm32-hal库(5)--usart串口通信三种模式(主从通信)(关于通信失败和串口不断发送数据问题的解决)
问题: 最近发现,stm32cubemx最新版本f1系列的hal库(1.85版本)生成的hal库,其中stm32f1xx_hal_uart.c的库文件中,其串口发送接收存在一些问题: 1.没有使用 __HAL_LOCK 和 __HAL_UNLOCK 宏&…...
一文学会LVS:概念、架构、原理、搭建过程、常用命令及实战案例
引言 随着互联网技术的飞速发展,服务器负载均衡技术变得越来越重要。LVS(Linux Virtual Server)作为一种高效的负载均衡解决方案,广泛应用于各大企业的生产环境中。本文将深入探讨LVS的概念、架构、工作原理,详细讲解其…...
[Go 微服务] Kratos 使用的简单总结
文章目录 1.Kratos 简介2.传输协议3.日志4.错误处理5.配置管理6.wire 1.Kratos 简介 Kratos并不绑定于特定的基础设施,不限定于某种注册中心,或数据库ORM等,所以您可以十分轻松地将任意库集成进项目里,与Kratos共同运作。 API -&…...
【unity实战】使用旧输入系统Input Manager 写一个 2D 平台游戏玩家控制器——包括移动、跳跃、滑墙、蹬墙跳
最终效果 文章目录 最终效果素材下载人物环境 简单绘制环境角色移动跳跃视差和摄像机跟随效果奔跑动画切换跳跃动画,跳跃次数限制角色添加2d物理材质,防止角色粘在墙上如果角色移动时背景出现黑线条方法一方法二 墙壁滑行实现角色滑墙不可以通过移动离开…...
【实战】EasyExcel实现百万级数据导入导出
文章目录 前言技术积累实战演示实现思路模拟代码测试结果 前言 最近接到一个百万级excel数据导入导出的需求,大概就是我们在进行公众号API群发的时候,需要支持500w以上的openid进行群发,并且可以提供发送openid数据的导出功能。可能有的同学…...
Graalvm配置文件与Feature和Substitute机制介绍
GraalVM介绍 GraalVM提前将Java应用程序编译成独立与机器码二进制文件(可执行文件、动态库文件),如windows系统中的exe文件和dll文件。与在Java虚拟机(JVM)上运行的应用程序相比,这些二进制文件更小,启动速…...
Appium adb 获取appActivity
方法一(最简单有效的方法) 通过cmd命令,前提是先打开手机中你要获取包名的APP adb devices -l 获取连接设备详细信息 adb shell dumpsys activity | grep mFocusedActivity 有时获取到的不是真实的Activity 方法二 adb shell monkey -p …...
调整分区失败致盘无法访问:深度解析与数据恢复全攻略
调整分区失败盘打不开的困境 在计算机的日常维护与管理中,调整磁盘分区是常见的操作之一,旨在优化存储空间布局、提升系统性能或满足特定应用需求。然而,当这一操作未能如预期般顺利进行,反而导致分区调整失败,进而使…...
试用笔记之-汇通计算机等级考试软件一级Windows
首先下载汇通计算机等级考试软件一级Windows http://www.htsoft.com.cn/download/htwork.rar...
Java的NIO体系
目录 NIO1、操作系统级别下的IO模型有哪些?2、Java语言下的IO模型有哪些?3、Java的NIO应用场景?相比于IO的优势在哪?4、Java的IO、NIO、AIO 操作文件读写5、NIO的核心类 :Buffer(缓冲区)、Channelÿ…...
基于SDR与FPGA的全栈开源Wi-Fi设计:openwifi架构解析与实战
1. 项目概述:当Wi-Fi遇见SDR,一个开源全栈无线设计的诞生如果你和我一样,在无线通信领域摸爬滚打多年,从研究协议栈到调试硬件驱动,总会遇到一个痛点:商用Wi-Fi芯片就像一个黑盒子。你能用iwconfig配置它&a…...
3步免费解锁WeMod完整功能:WandEnhancer终极使用指南
3步免费解锁WeMod完整功能:WandEnhancer终极使用指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 还在为WeMod的高级功能付费而烦恼吗&am…...
因促达促进长高作用原理
因促达促进长高的作用机理:因促达是生长因子促进剂(IGF-1 Promotion)与γ-氨基丁酸骨胶原蛋白肽压片糖果的组合,同时作用于GH-IGF-1生长轴的三个靶点,实现更全面、更直接、更有效的效果。针对生长轴的第一个靶点&#…...
AI智能体安全审计实战:构建可插拔的安全技能库
1. 项目概述:一个面向AI智能体的安全审计技能库最近在折腾AI智能体(Agent)的开发,发现一个挺有意思的现象:大家把大量精力都花在了让智能体“更聪明”上,比如提升其推理能力、扩展工具调用范围,…...
OpenAshare:本地化AI开发工具集,模块化集成Ollama与LangChain
1. 项目概述:一个为开发者打造的本地化AI工具集最近在GitHub上闲逛,发现了一个挺有意思的项目,叫“OpenAshare”。初看这个名字,你可能会联想到“开源分享”之类的概念,但点进去之后,我发现它的定位远比一个…...
木质防火门基础选购核心要点
在现代建筑消防配套设施体系中,木质防火门凭借外观质感柔和、适配各类室内装修风格、现场安装便捷灵活等优势,被广泛应用于住宅楼宇、商业综合体、办公写字楼、酒店公寓等各类民用与公共建筑场景,是建筑防火分隔、阻断烟火蔓延的核心安防构件…...
NotebookLM播客化军规级配置(仅限前500名开发者获取的prompt工程模板+声学环境补偿表)
更多请点击: https://intelliparadigm.com 第一章:NotebookLM播客化军规级配置全景导览 NotebookLM 的播客化(Podcasting)能力并非开箱即用,需通过严格配置激活其语音合成、语义分段与上下文锚定三大核心能力。以下为…...
群晖使用git遇到的问题
文章目录使用流程:多用户说明注意补充使用流程: 这是为了解决每次使用都需要输入密码的问题 1,在windows上,使用命令 生成公私钥对 ssh-keygen -t ed25519会在 C:\Users\你的用户名.ssh\下生成 id_ed25519 id_ed25519.pub2,将…...
AI智能体规划框架skill-daydreaming:让AI像人一样思考与执行复杂任务
1. 项目概述与核心价值最近在GitHub上看到一个挺有意思的项目,叫“skill-daydreaming”,作者是regiep4。光看这个名字,你可能觉得有点玄乎——“技能白日梦”?这到底是干嘛的?作为一个在AI和自动化工具领域折腾了十多年…...
偏移重载双缸同步电液伺服控制【附代码】
✨ 长期致力于电液伺服系统、双缸同步、联合仿真、力/位切换控制、模糊RBF神经网络PID控制研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)双缸力/位切…...
