React Hooks的使用(三)——useRef、useImperativeHandle、useLayoutEffect解析、自定义Hook

一、useRef

useRef返回一个ref对象,返回的ref对象再组件的整个生命周期保持不变

最常用的ref是两种用法:

  • 用法一:引入DOM(或者组件,但是需要是class组件)元素;
    案例一:引用DOM
    在这里插入图片描述
import React, {useRef} from "react";class TestCpn extends React.Component{render() {return <h2>TestCpn</h2>}
}function TestCpn2(props) {return <h2>TestCpn2</h2>
}export default function RefHookDemo01() {const titleRef = useRef()const inputRef = useRef()const testRef = useRef()const testRef2 = useRef()function changeDOM() {titleRef.current.innerHTML = 'hello world'inputRef.current.focus()console.log(testRef.current)console.log(testRef2.current)}return (<div><h2 ref={titleRef}>RefHookDemo01</h2><input type="text" ref={inputRef}/><TestCpn ref={testRef} /><TestCpn2 ref={testRef2} /><button onClick={e => changeDOM()}>修改DOM</button></div>)
}
  • 用法二:保存一个数据,这个对象在整个生命周期中可以保存不变;
    案例二:使用ref保存上一次的某一个值
    在这里插入图片描述
import React, {useEffect, useRef, useState} from "react";export default function RefHookDemo02() {const [count, setCount] = useState(0)const numRef = useRef(count)useEffect(() => {numRef.current = count}, [count])return (<div>{/*<h2>numRef中的值: {numRef.current}</h2>*/}{/*<h2>count中的值: {count}</h2>*/}<h2>count上一次的值:{numRef.current}</h2><h2>count当前的值:{count}</h2><button onClick={e => setCount(count + 10)}>+10</button></div>)
}

二、useImperativeHandle

useImperativeHandle并不是特别好理解,我们一点点来学习。

我们先来回顾一下ref和forwardRef结合使用:

  • 通过forwardRef可以将ref转发到子组件;
  • 子组件拿到父组件中创建的ref,绑定到自己的某一个元素中;
    在这里插入图片描述
import React, {forwardRef, useRef} from "react";const HYInput = forwardRef((props,ref) => {return <input ref={ref} type="text"/>}
)export default function ForwardRefDemo() {const inputRef = useRef()return (<div><HYInput ref={inputRef}/><button onClick={e => inputRef.current.focus()}>聚焦</button></div>)
}

forwardRef的做法本身没有什么问题,但是我们是将子组件的DOM直接暴露给了父组件:

  • 直接暴露给父组件带来的问题是某些情况的不可控;
  • 父组件可以拿到DOM后进行任意的操作;
  • 但是,事实上在上面的案例中,我们只是希望父组件可以操作的focus,其他并不希望它随意操作;

通过useImperativeHandle可以只暴露固定的操作:

  • 通过useImperativeHandle的Hook,将传入的ref和useImperativeHandle第二个参数返回的对象绑定到了一起;
  • 所以在父组件中,使用 inputRef.current时,实际上使用的是返回的对象
  • 比如我调用了 focus函数;
    在这里插入图片描述
import React, {forwardRef, useImperativeHandle, useRef} from "react";const HYInput = forwardRef((props, ref) => {const inputRef = useRef()useImperativeHandle(ref, () => {return {focus: () => {inputRef.current.focus()console.log('useImperativeHandle中回调函数返回的对象里面的focus')}}}, [inputRef.current])return <input ref={inputRef} type="text"/>}
)export default function ForwardRefDemo02() {const inputRef = useRef()return (<div><HYInput ref={inputRef}/><button onClick={e => inputRef.current.focus()}>聚焦</button></div>)
}

三、useLayoutEffect

useLayoutEffect看起来和useEffect非常的相似,事实上他们也只有一点区别而已:

  • useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新;
  • useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新

如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect。
案例: useEffect和useLayoutEffect的对比
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、自定义Hook

自定义Hook本质上只是一种函数代码逻辑的抽取,严格意义上来说,它本身并不算React的特性。

需求0:所有的组件在创建和销毁时都进行打印

  • 组件被创建:打印 组件被创建了;
  • 组件被销毁:打印 组件被销毁了;

在这里插入图片描述

import React, {useEffect} from "react";
const Home = (props) => {useEffect(() => {console.log('Home组件被创建出来了~')return () => {console.log('Home组件被销毁了!')}}, [])return <h2>Home</h2>
}
const Profile = (props) => {useEffect(() => {console.log('Profile组件被创建出来了~')return () => {console.log('Profile组件被销毁了!')}}, [])return <h2>Profile</h2>
}
export default function CustomHookLifeDemo01() {useEffect(() => {console.log('CustomHookLifeDemo01组件被创建出来了~')return () => {console.log('CustomHookLifeDemo01组件被销毁了!')}}, [])return (<div><h2>CustomHookLifeDemo01</h2><Home /><Profile /></div>)
}

在这里插入图片描述

import React, {useEffect} from "react";
const Home = (props) => {useLoggingLife('Home')return <h2>Home</h2>
}
const Profile = (props) => {useLoggingLife('Profile')return <h2>Profile</h2>
}
export default function CustomHookLifeDemo01() {useLoggingLife('CustomHookLifeDemo01')return (<div><h2>CustomHookLifeDemo01</h2><Home /><Profile /></div>)
}
function useLoggingLife(name) {useEffect(() => {console.log(`${name}组件被创建出来了~`)return () => {console.log(`${name}组件被销毁了!`)}}, [])
}

需求一:Context的共享

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

import {useContext} from "react";
import {TokenContext, UserContext} from "../App";function useUserContext() {const user = useContext(UserContext)const token = useContext(TokenContext)return [user, token]
}export default useUserContext

需求二:获取鼠标滚动位置

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

需求三:localStorage数据存储

在这里插入图片描述

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

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

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

相关文章

python制作聊天机器人原理_用 Python 来做一个聊天机器人吧!(一)

在我的一个回答里&#xff0c;我提到了用 Python 搭建聊天机器人。从今天开始&#xff0c;我就带着大家从0开始搭建一个聊天机器人。(顺便说一句&#xff0c;我喜欢把链接像上面这样加在文字里&#xff0c;如果找不到文中所说的资源&#xff0c;可以看看周围有没有链接。)准备工…

python子类分配

原问题是将左边样式变成右边样式&#xff1a; 即有父类和子类&#xff0c;父类包括多个子类&#xff0c;怎样将子类匹配到父类下面的问题 代码如下 1 #!/usr/bin/python3.42 # -*- coding: utf-8 -*-3 4 arr1 ["S01","S01","S01","S02&quo…

react 网易云音乐实战项目笔记

0、项目规范 一、路由相关 npm i react-router-dom npm i react-router-config // 用于配置路由映射的关系数组1. 路由重定向 访问 /路径 》 重定向到 /discover路径 2. 二级路由&#xff1a; 二、网络请求相关 npm i axios页面中使用暴露 出来的request发送网络请求&#…

catchlog是什么软件_Log 重要性

有一项目.Linux Tomcat Jdk1.6 配置.第一版已经完成,部署成功.但很长时间过去了.一年有余,客户突然要加个小功能,且还有个地方要改.功能,对编码的难度是微乎其微的.由于改动的功能比较偏,所以回归测试也比较轻松的通过.但在再次部署的时候出现了.众所周知,JAVA开发最终需要的…

java 几个线程池的理解

http://www.cnblogs.com/dolphin0520/p/3932921.html 这个文章写的很好 转载于:https://www.cnblogs.com/elnino/p/5807713.html

react项目打包

一、react项目打包 对于使用脚手架创建的项目&#xff0c;打包是一件非常容易的事情&#xff1a; yarn build其他文件没有太多要解析的&#xff0c;我们看一下js文件&#xff1a; [hash].chunk.js 代表是所有依赖的第三方库&#xff0c; vendor(第三方库) 的代码&#xff1b…

spark应用程序转换_Spark—RDD编程常用转换算子代码实例

Spark—RDD编程常用转换算子代码实例Spark rdd 常用 Transformation 实例&#xff1a;1、def map[U: ClassTag](f: T > U): RDD[U] 将函数应用于RDD的每一元素&#xff0c;并返回一个新的RDDpackagetop.ruandbimportorg.apache.spark.{SparkConf, SparkContext}object Rdd…

struts2中一些常用的写法 记录

1.对日期进行处理 Date current new Date(); java.text.SimpleDateFormat sdf new java.text.SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); String time sdf.format(current); 或者&#xff1a; 插入当前时间&#xff1a;pstmt.setDate(4,new java.sql.Date(new ja…

React SSR

一、为什么需要SSR呢&#xff1f; 单页面富应用的局限&#xff1a; 之前我们开发的应用程序&#xff0c;如果直接请求可以看到上面几乎没有什么内容。 但是为什么我们页面可以看到大量的内容呢&#xff1f; 因为当我们请求下来静态资源之后会执行JS&#xff0c;JS会去请求数…

linux 命令 读phy_PHY LINUX (转载整理)

每每分析网络问题的时候&#xff0c;总要梳理层次关系&#xff0c;本想自己写一个关于PHY的文档&#xff0c;找到网上有人写的一篇比较好&#xff0c;所以转载下来&#xff0c;仅供初学者参考。以太网 MAC(链路层)PHY(物理层/RTL8201F,88E1111);集成型DM9000&#xff0c;RTL813…

Laravel框架开发规范-修订版

1.PHP编码规范 1.1 标签 PHP 程序可以使用<?php ?>或<? ?>来界定PHP代码 在HTML 页面中嵌入纯变量时&#xff0c;使用<? ?>这样的形式 纯PHP类文件&#xff0c;文件开始标签使用<?php&#xff0c;闭合标签?>必须省略 1.2 编码 PHP文件必须使用…

vue显示两位小数的方法_Vue toFixed保留两位小数的3种方式

Vue toFixed保留两位小数的3种方式第一种&#xff1a;直接写在js里面&#xff0c;这是最简单的val.toFixed(2)第二种&#xff1a;在ElementUi表格中使用第三种&#xff1a;在取值符号中使用 {{}}定义一个方法towNumber(val) {return val.toFixed(2)}使用{{ towNumber(row.equiV…

Tyvj 1176 火焰巨魔的惆怅

Tyvj 1176 火焰巨魔的惆怅 背景 TYVJ2月月赛第一道巨魔家族在某天受到了其他种族的屠杀&#xff0c;作为一个英雄&#xff0c;他主动担任了断后的任务&#xff0c;但是&#xff0c;在巨魔家族整体转移过后&#xff0c;火焰巨魔却被困住了&#xff0c;他出逃的方式也只有召唤小火…

Vue3 组件通信学习笔记

一、父子组件之间通信 父子组件之间如何进行通信呢&#xff1f; 父组件传递给子组件&#xff1a;通过props属性&#xff1b;子组件传递给父组件&#xff1a;通过$emit触发事件&#xff1b; 1.1 父组件传递给子组件 在开发中很常见的就是父子组件之间通信&#xff0c;比如父…

js调用vlc_如何使用HTML5或JavaScript查看RTSP流,而不使用Real Player插件上的VLC插件等插件?...

The idea is to develop a cross-platform, standalone application that could play a video, streamed over RTSP, using HTML5 or JavaScript or any other web technology.解决方案RTSP is a protocol on the same level as HTTP. Its impossible to do RTSP via HTTP.The …

HDU-3729 二分匹配 匈牙利算法

题目大意&#xff1a;学生给出其成绩区间&#xff0c;但可能出现矛盾情况&#xff0c;找出合理组合使没有说谎的人尽可能多&#xff0c;并按maximum lexicographic规则输出组合。 //用学生去和成绩匹配&#xff0c;成绩区间就是学生可以匹配的成绩#include <iostream> #i…

Vue3 slot插槽——(默认插槽、具名插槽、作用域插槽)

一、认识插槽Slot 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a; 前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b;但是为了让这个组件具备更强的通用性&#xff0c;我们不能将组件中的内容限制为固定的div、span等等这…

dbcc dbreindex server sql_DBCC DBREINDEX重建索引提高SQL Server性能

DBCC DBREINDEX重建索引提高SQL Server性能[转载]大多数SQL Server表需要索引来提高数据的访问速度&#xff0c;如果没有索引&#xff0c;SQL Server要进行表格扫描读取表中的每一个记录才能找到索要的数据。索引可以分为簇索引和非簇索引&#xff0c;簇索引通过重排表中的数据…

Vue动态组件和组件缓存

一、切换组件案例 比如我们现在想要实现了一个功能&#xff1a; 点击一个tab-bar&#xff0c;切换不同的组件显示&#xff1b; 这个案例我们可以通过两种不同的实现思路来实现&#xff1a; 方式一&#xff1a;通过v-if来判断&#xff0c;显示不同的组件&#xff1b; 方式二…

hidl 原理分析_一个 health service 不生效问题引出的一点知识

从 Android P 开始&#xff0c;Google 开始推荐厂家再定制一个 health 。前不久遇到一个定制 health 中的信息未成功反应到 Framework 的问题&#xff0c;在分析解决问题的过程中&#xff0c;学习到了一点新知识&#xff0c;所以就在这篇文章里根据解决问题的流程做一个小小的记…