从变量的角度理解 Hooks , 变得更简单了
从变量角度理解Hooks
在React的世界里,Hooks的引入为函数式组件带来了前所未有的灵活性和能力。它们让我们得以完全摆脱class
式的写法,在函数式组件中完成生命周期管理、状态管理、逻辑复用等几乎全部组件开发工作。这次,我们就从变量的角度来深入理解一下这些强大的Hooks。
一、useState:定义自变量
想象一下,我们有一个自变量x
,它代表组件的某个状态。在React中,我们可以使用useState
来定义这个自变量:
const [x, setX] = useState(0);
这里,x
就是我们的自变量,而setX
是一个函数,用于改变x
的值。
接下来,我们定义一个因变量y
,它是x
的函数:
const y = 2 * x + 1;
每次x
变化时,y
都会随之更新。
为了演示这个过程,我们可以创建一个简单的点击事件,每次点击时x
增加1:
export default function App() {const [x, setX] = useState(0);const y = 2 * x + 1;const changeX = () => setX(x + 1);return (<ul onClick={changeX}><li>x是{x}</li><li>y是{y}</li></ul>);
}
二、useMemo & useCallback:缓存因变量
在上面的例子中,每次组件重新渲染时,y
和changeX
都会重新计算。但在复杂的业务场景中,这些计算可能会变得非常昂贵。为了优化性能,我们可以使用useMemo
和useCallback
来缓存这些因变量。
useMemo
用于缓存一个数据类型的因变量:
//const y = 2 * x + 1;
const y = useMemo(() => 2 * x + 1, [x]);
而useCallback
则用于缓存一个函数类型的因变量:
//const changeX = () => setX(x + 1);
const changeX = useCallback(() => setX(x + 1), [x]);
这两个Hooks都接收一个创建函数和一个依赖项数组作为参数。只要依赖项不变,它们就会返回缓存的值或函数,从而避免不必要的计算。
三、useEffect:处理副作用
在函数式编程中,副作用是指一个函数在固定的输入下产生不固定的输出。在React中,副作用通常包括修改DOM、发起网络请求、设置定时器等。
为了处理这些副作用,我们可以使用useEffect
。它允许我们定义一个函数,在组件渲染后执行副作用逻辑。
例如,我们希望当x
变化时,将页面标题修改为x
的值:
useEffect(() => {document.title = x;
}, [x]);
这里,
useEffect
接收一个函数和一个依赖项数组。当依赖项变化时,函数会被执行。
四、useReducer:管理复杂状态
当组件的状态变得复杂时,我们可以使用useReducer
来管理它们。useReducer
可以看作是useState
的进阶版,它使用Redux的理念,将多个状态合并为一个状态对象,并通过一个reducer函数来更新状态。
- useReducer 和 redux 中 reducer 很像
- useState 内部就是靠 useReducer 来实现的
- useState 的替代方案,它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法
- 在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等
let initialState = 0;
// 如果你希望初始状态是一个{number:0}
// 可以在第三个参数中传递一个这样的函数 ()=>({number:initialState})
// 这个函数是一个惰性初始化函数,可以用来进行复杂的计算,然后返回最终的 initialState
const [state, dispatch] = useReducer(reducer, initialState, init);
这里,state
是我们的状态对象,dispatch
是一个函数,用于触发状态更新。
const initialState = 0;
function reducer(state, action) {switch (action.type) {case 'increment':return {number: state.number + 1};case 'decrement':return {number: state.number - 1};default:throw new Error();}
}
function init(initialState){return {number:initialState};
}
function Counter(){const [state, dispatch] = useReducer(reducer, initialState,init);return (<>Count: {state.number}<button onClick={() => dispatch({type: 'increment'})}>+</button><button onClick={() => dispatch({type: 'decrement'})}>-</button></>)
}
五、useContext: 跨组件层级传递自变量
useContext
允许你在组件树中跨多层级访问context(上下文)的值,而无需通过每层手动传递props。以下是对useContext的详细解释:
1、定义与功能
- 定义:useContext是一个React Hook,用于读取和订阅React组件中的context。
- 功能:它能够在组件树中共享数据,使得数据可以在不同层级的组件之间传递,而无需通过props逐层传递。
2、使用方式
- 创建Context:首先,你需要使用React.createContext()方法创建一个context对象。这个对象不保存数据,但它作为数据的载体,允许你从组件中获取或向组件提供数据。
- 提供数据:然后,你需要在组件树中使用Context.Provider包裹那些需要访问context的组件,并通过value属性向Provider提供数据。
- 读取数据:在需要访问context的组件中,你可以使用useContext Hook来读取context的值。你需要将先前创建的context对象作为参数传递给useContext。
3、示例
以下是一个简单的示例,展示了如何使用useContext在组件之间共享数据:
import React, { createContext, useContext, useState } from 'react';// 创建一个Context对象
const MyContext = createContext('defaultValue');function App() {// 使用useState创建一个state,并通过Provider将其提供给后代组件const [value, setValue] = useState('newValue');return (<MyContext.Provider value={value}><ChildComponent /><ButtonComponent /></MyContext.Provider>);
}function ChildComponent() {// 在子组件内使用useContext获取context的值const contextValue = useContext(MyContext);return <div>Child Component: {contextValue}</div>;
}function ButtonComponent() {// 假设这里有一个函数用于修改context的值(实际中可能需要通过某种方式触发这个函数)const handleClick = () => {// 这里需要一种方式来修改Provider中的value,通常是通过某种状态管理或回调函数实现// 例如,可以使用useReducer或其他状态管理库来更新value};return <button onClick={handleClick}>Change Context Value</button>;
}export default App;
注意:在这个示例中,ButtonComponent组件需要一种方式来修改Provider中的value。在实际应用中,这通常是通过某种状态管理(如useState、useReducer)或回调函数来实现的。由于这个示例是为了说明useContext的用法,所以并没有展示如何修改value的具体实现。
4、注意事项
(1) Provider嵌套:Provider组件可以嵌套使用,这样你就可以在不同的层级提供不同的context值。
(2) 性能优化:当context的值发生变化时,React会自动重新渲染那些读取了该context的组件。为了避免不必要的重渲染,你可以使用React.memo或shouldComponentUpdate等优化技术。
(3) 默认值:如果在组件树中没有找到对应的Provider,useContext会返回传递给createContext的defaultValue。
总的来说,useContext是React中一个非常有用的Hook,它能够帮助你在组件之间共享数据,从而简化组件间的通信和状态管理。
六、useRef:增加灵活性
最后,useRef
作为一个标记变量,提供了一种在组件的整个生命周期内持久存储数据的方法 , 并作用于自变量与因变量的不同路径中。它增加了组件逻辑的灵活性,允许我们在组件的生命周期内持久地存储数据。
以下是对useRef的详细解释:
1、定义与功能
- 定义:useRef是一个React Hook,它返回一个可变的ref对象,其
.current
属性被初始化为传递给useRef的参数(在组件的整个生命周期内保持不变)。 - 功能:useRef主要用于两个场景:访问DOM元素和保存跨渲染周期的变量。
2、使用场景
-
访问DOM元素:
- 当需要直接访问DOM元素(如设置焦点、测量尺寸等)时,可以使用useRef。
- 通过将ref对象传递给元素的
ref
属性,可以在组件中通过ref.current
访问该元素。
-
保存跨渲染周期的变量:
- useRef返回的ref对象在组件的整个生命周期内保持不变,因此可以用于存储不需要触发组件重新渲染的变量。
- 这使得useRef成为保存上一次渲染状态、在自定义Hook中共享数据等场景的理想选择。
3、示例
以下是一个使用useRef访问DOM元素和保存跨渲染周期变量的示例:
import React, { useRef } from 'react';function AutoFocusInput() {// 创建一个ref对象用于访问DOM元素const inputRef = useRef(null);// 处理按钮点击事件,使输入框获得焦点const handleButtonClick = () => {inputRef.current.focus();};// 创建一个ref对象用于保存跨渲染周期的变量const counterRef = useRef(0);// 增加计数器的值(不会触发组件重新渲染)const incrementCounter = () => {counterRef.current += 1;};return (<div><input type="text" ref={inputRef} /><button onClick={handleButtonClick}>聚焦输入框</button><p>计数器值:{counterRef.current}</p><button onClick={incrementCounter}>增加计数器</button></div>);
}export default AutoFocusInput;
在这个示例中,inputRef
用于访问输入框DOM元素,并在按钮点击时使其获得焦点。counterRef
用于保存一个计数器变量,并通过按钮点击事件增加其值。由于useRef返回的ref对象在组件的整个生命周期内保持不变,因此可以在多次渲染之间保持计数器的值。
4、注意事项
(1) 不要滥用useRef:虽然useRef可以在不触发组件重新渲染的情况下存储数据,但它不应该被用作主要的状态管理工具。对于需要响应状态变化的数据,应该使用useState或useReducer等状态管理Hook。
(2) 与class组件中的refs对比:在class组件中,refs是通过React.createRef()
创建的,并在componentDidMount
、componentDidUpdate
等生命周期方法中访问DOM元素。而在函数组件中,useRef提供了一种更简洁的方式来创建和使用refs。
总之,useRef是React中一个非常有用的Hook,它提供了在组件的整个生命周期内持久存储数据的方法,而不会触发组件的重新渲染。这使得它在访问DOM元素和保存跨渲染周期变量等场景中非常有用。
总结
从变量的角度来看,React Hooks的本质是自变量与因变量的关系。useState
用于定义自变量,useMemo
和useCallback
用于定义无副作用的因变量,useEffect
用于定义有副作用的因变量。为了方便操作更多的自变量,我们有了useReducer
;为了跨组件层级操作自变量,我们有了useContext
;最后,为了让组件逻辑更灵活,我们有了useRef
。
通过这些Hooks,我们可以在函数式组件中轻松实现复杂的逻辑和状态管理,享受React带来的高效和便捷。
相关文章:
从变量的角度理解 Hooks , 变得更简单了
从变量角度理解Hooks 在React的世界里,Hooks的引入为函数式组件带来了前所未有的灵活性和能力。它们让我们得以完全摆脱class式的写法,在函数式组件中完成生命周期管理、状态管理、逻辑复用等几乎全部组件开发工作。这次,我们就从变量的角度…...
LabVIEW Modbus通讯稳定性提升
在LabVIEW开发Modbus通讯程序时,通讯不稳定是一个常见问题,可能导致数据丢失、延迟或错误。为了确保通讯的可靠性,可以从多个角度进行优化,以下是一些有效的解决方案,结合实际案例进行分析。 1. 优化通讯参数设置 通讯…...
(8) cuda分析工具
文章目录 Nvidia GPU性能分析工具Nsight SystemNvidia GPU性能分析工具Nsight System Nvidia GPU性能分析工具Nsight System NVIDIA Nsight Systems是一个系统级的性能分析工具,用于分析和优化整个CUDA应用程序或系统的性能。它可以提供对应用程序整体性能的全面见…...
C语言 | Leetcode C语言题解之第517题超级洗衣机
题目: 题解: int findMinMoves(int* machines, int machinesSize){int sum0;for(int i0;i<machinesSize;i){summachines[i];}if(sum%machinesSize!0){return -1;}int psum/machinesSize;int ans0;int cur0;for(int i0;i<machinesSize;i){cur(mac…...
Java多线程编程基础
目录 编写第一个多线程程序 1. 方式一 : 继承Thread类, 重写run方法 2. 方式二: 实现Runnable接口, 重写run方法 3. 方式三: 使用Lambda表达式 [匿名内部类] [Lambda表达式] 在上个文章中, 我们了解了进程和线程的相关概念. 那么, 在Java中, 我们如何进行多线程编程呢? …...
刷代随有感(134):单调栈——下一个更大元素I(难点涉及哈希表与单调栈的结合)
单调栈处理的是下标! 题干: 代码: class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {stack<int>ddst;unordered_map<int,int>umap;vector<int…...
Linux云计算 |【第五阶段】CLOUD-DAY5
主要内容: 容器的镜像编排,commit简单镜像创建,Dockerfile制作服务镜像(语法、创建镜像)、创建复杂镜像(Docker微服务架构、示例:NGINXPHP)、私有仓库 一、简单镜像创建 1、自定义…...
被上传文件于后端的命名策略
上一篇博客我们了解了前端上传的文件资源应该存放在后端项目中的什么位置,那么随之而来的另一个问题——我们应该如何为上传的文件命名呢?往往直接采用原文件名并不稳妥,会导致命名冲突、文件冲突、数据库管理冲突等多种问题,下面…...
哈希表 算法专题
哈希表简介 是什么 存储数据的容器有啥用? "快速"查找某个元素什么时候用哈希表 频繁地查找某个数(有序用二分)怎么用哈希表 容器用数组模拟 字符串中的字符 范围比较小的数 一. 两数之和 两数之和 class Solution {public int[] twoSum(int[] nums, int targe…...
unity3d————[HideInInspector]
在Unity3D中,[HideInInspector]是一个属性修饰符,它的主要作用是在Unity的Inspector窗口中隐藏变量或属性。以下是关于[HideInInspector]的详细解释和作用: 作用 隐藏变量或属性:当你在脚本中使用[HideInInspector]修饰符时&…...
Soanrquber集成Gitlab 之 导入Gitlab项目
集成Gitlab 之 导入Gitlab项目 说明: Sonarquber里面的项目,顺便设置,只要在集成CI的时候,使用这个项目的项目标识即可。 当然项目名称一一对应是最好的了,所以这里讲导入Gitlab的项目,项目名称一一对应&…...
论区块链技术及应用
引言 区块链技术作为一种革命性的创新,近年来在全球范围内得到了广泛关注和应用。其去中心化、透明性和不可篡改的特性,使其在多个领域展现出了巨大的潜力。从金融到物联网,从医疗管理到政务监管,区块链正在改变我们处理信息和进…...
GPT避坑指南:如何辨别逆向、AZ、OpenAI官转
市面上有些说自己是官转,一刀只需要1块甚至几毛钱,并声称官方倍率的,很大可能就是使用的是 逆向或Azure。 如何鉴别逆向 逆向的种类很多,主要分为3类 逆向不知名A| 镜像站或偷的 key。成本约等于0,调用聊天数据可能在…...
Qt 文本文件读写与保存
Qt 文本文件读写与保存 开发工具:VS2013 QT5.8 设计UI界面,如下图所示 sample7_1QFile.h 头文件: #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample7_1QFile.h"class sample7_1QFile : public QMainWin…...
Linux基础环境搭建(CentOS7)- 安装Scala和Spark
#Linux基础环境搭建(CentOS7)- 安装Scala和Spark Linux基础环境搭建(CentOS7)- 安装Scala和Spark 大家注意以下的环境搭建版本号,如果版本不匹配有可能出现问题!(spark不要下2.4版本的 会报错…...
SpringBoot 下的Excel文件损坏与内容乱码问题
序言 随着打包部署的方式的改变,原本正常运行的代码可能带来一些新的问题,比如我们现在使用SpringBoot 的方式生成Jar包直接运行,就会对我们再在Resource下的Excel文件产生影响,导入与预期不符的情况发生cuiyaonan2000163.com 比…...
官宣下代GPU存在缺陷,50系显卡或将迎来涨价
如果说 AMD 在 Ryzen 3000 系列还是和 intel 在 CPU 方面棋差一着的话,Ryzen 5000 系列就是打了个漂亮的翻身仗了。 凭借先进的 7nm 工艺制程和全新架构,让后来 intel 急忙推出「14nm」的 11 代酷睿也难以望其项背。 直到 intel 12 代发布的时候…...
使用pytorch实现LSTM预测交通流
原始数据: 免费可下载原始参考数据 预测结果图: 根据测试数据test_data的真实值real_flow,与模型根据测试数据得到的输出结果pre_flow 完整源码: #!/usr/bin/env python # _*_ coding: utf-8 _*_import pandas as pd import nu…...
C/C++(八)C++11
目录 一、C11的简介 二、万能引用与完美转发 1、万能引用:模板中的 && 引用 2、完美转发:保持万能引用左右值属性的解决方案 三、可变参数模板 1、可变参数模板的基本使用 2、push 系列和 emplace 系列的区别 四、lambda表达式…...
使用three.js 实现 自定义绘制平面的效果
使用three.js 实现 自定义绘制平面的效果 预览 import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.jsconst box document.getElementById(box)const scene new THREE.Scene()const camera new THREE.PerspectiveCam…...
玩转Docker | 使用Docker部署捕鱼网页小游戏
玩转Docker | 使用Docker部署捕鱼网页小游戏 一、项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署捕鱼网页小游戏下载镜像创建容器检查容器状态下载项目内容查看服务监听端口安全设置四、访问捕鱼网页小游戏五、总结一、项目介绍…...
第2章 Android App开发基础
第 2 章 Android App开发基础 bilibili学习地址 github代码地址 本章介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一 样,App工程是怎样的组织结构又是怎样配置的,App开发的前后端分离设计…...
通过 SYSENTER/SYSEXIT指令来学习系统调用
SYSENTER指令—快速系统调用 指令格式没有什么重要的内容,只有opcode ,没有后面的其他字段 指令的作用: 执行快速调用到特权级别0的系统过程或例程。SYSENTER是SYSEXIT的配套指令。该指令经过优化,能够为从运行在特权级别3的用户代码到特权级别0的操作系统或执行过程…...
Nginx开发实战——网络通信(一)
文章目录 Nginx开发框架信号处理函数的进一步完善(避免僵尸子进程)(续)ngx_signal.cxxngx_process_cycle.cxx 网络通信实战客户端和服务端1. 解析一个浏览器访问网页的过程2.客户端服务器角色规律总结 网络模型OSI 7层网络模型TCP/IP 4层模型3.TCP/IP的解释和比喻 最…...
w外链如何跳转微信小程序
要创建外链跳转微信小程序,主要有以下几种方法: 使用第三方工具生成跳转链接: 注册并登录第三方外链平台:例如 “W外链” 等工具。前往该平台的官方网站,使用手机号、邮箱等方式进行注册并登录账号。选择创建小程序外…...
获取平台Redis各项性能指标
业务场景 在XXXX项目中把A网的过车数据传到B网中,其中做了一个业务处理,就是如果因为网络或者其他原因导致把数据传到B网失败,就会把数据暂时先存到redis里,并且执行定时任务重新发送失败的。 问题 不过现场的情况比较不稳定。出…...
STM32 HAL 点灯
首先从点灯开始 完整函数如下: #include "led.h" #include "sys.h"//包含了stm32f1xx.h(包含各种寄存器定义、中断向量定义、常量定义等)//初始化GPIO口 void led_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开…...
【http作业】
1.关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld #关闭防火墙 [rootlocalhost ~]# setenforce 0 2.下载nginx包 [rootlocalhost ~]# mount /dev/sr0 /mnt #挂载目录 [rootlocalhost ~]# yum install nginx -y #下载nginx包 3.增加多条端口 [rootlocalhost ~]# n…...
WPF+MVVM案例实战(十一)- 环形进度条实现
文章目录 1、运行效果2、功能实现1、文件创建与代码实现2、角度转换器实现3、命名空间引用3、源代码下载1、运行效果 2、功能实现 1、文件创建与代码实现 打开 Wpf_Examples 项目,在Views 文件夹下创建 CircularProgressBar.xaml 窗体文件。 CircularProgressBar.xaml 代码实…...
简述MCU微控制器
目录 一、MCU 的主要特点: 二、常见 MCU 系列: 三、应用场景: MCU 是微控制器(Microcontroller Unit)的缩写,指的是一种小型计算机,专门用于嵌入式系统。它通常集成了中央处理器(…...
江宁区财政局网站开发区分局/搜索引擎营销的实现方法有
1.DB LUW简介: 1.DB LUW全称:Database Logical Unit of Work2.从数据库编程的角度来看,DB LUW 是一个不可分割的数据库操作序列,以事务的提交或回滚结束3.DB LUW 要么完全由数据库系统执行,要么根本不执行4.如果 DB LUW 中发生错误,则自 DB LUW 中所有数据库更改都将被回…...
自己做的html网页怎么发布/seo标题优化步骤
西湖区附近上门维修电脑费用池故障、电池不充电、电池不放电、使用电池不能开机、电池供电时间缩短专业电脑精修 网络布线 安防安装专业维修:台式机 笔记本 网络维护 安防 网络布线 数据恢复 笔记本除尘 苹果系统安装 维修打印机 维修复印机专为电脑用户提供软硬件上…...
个人网站首页/网络培训机构
转自:https://blog.csdn.net/wwt18811707971/article/details/107551124 1. 概述 电源完整性: 如何保证电源分配系统(Power Distribution Network—— PDN)满足负载芯片对电源的要求,即为电源完整性。 解释一下&…...
直播视频素材/seo关键词排名技术
磁盘管理:RAIDRedundent Aarry of Inexpensive DisksRedundent Aarry of Indepedent Disks目的:高性能(读、写)、可靠(冗余)级别:Level,用于描述磁盘不同组合逻辑Raid0: 条带Raid1: 镜像Raid10就是将Raid1和Raid0按某种方式连接起…...
网站建设毕业答辩ppt/如何创建网站平台
背景 项目中使用到List求交集,很容易想到collecion.retainAll()方法,但是在数据量比较大时,这个方法效率并不高。本文研究了几种常用的方法,以供大家参考。 方法 【首先】 梳理下思路,List去重一般有几种方法。 『…...
无锡seo网站管理/扬州网络推广哪家好
Samba原理和配置 个人原创,转载请注明,否则追究法律责任。 一,原理及安装 1,Samba是在Linux和UNIX系统上实现在局域网上共享文件一种通信协议,它为局域网内的不同计算机之间提供文件等资源的共享服务。 2,Samba访问…...