何为useRef

useRef是随着react函数式组件发展而来的,是react众多官方hook中的一个,调用useRef可以返回一个伴随这组件整个声明周期不发生改变的对象,这个对象常见的用途有两个:

  • 用于绑定dom元素,从而实现对dom元素的操作
  • 用于保存不希望随着组件重新渲染而改变的值,如定时器

在项目中的应用

我在做自己的网站时遇到过一些场景,实现效果与预想中的不一致,让我头大了好一阵子,所幸最终都得到了解决,为了在以后能够回来看一下,同时记录学习过程中的一些知识点,现将这两个场景记录如下。

一、编写自己的防抖函数

在编写登录注册功能时,需要对用户输入的信息进行校验,包括前端的校验以及和后端通信的校验,如果只是前端的校验还好,如果在用户输入的信息每次发生变化都去和服务器通信校验的话,大量的http请求会对服务器造成压力,所以我希望对这些行为进行防抖处理。

useDebounce.ts

import { useEffect, useRef } from "react"

export const useDebounce = (f:Function,delay:number)=>{
//使用useRef保存计时器,以此确保在组件更新时始终是同一个计时器,而不是重新创建
const {current} = useRef<{timmer:any}>({timmer:null}) useEffect(()=>{
return ()=>{
//组件销毁时清除计时器
clearTimeout(current.timmer)
}
},[])
return function(...args:any[]){
//如果计时器存在,则清除该计时器
if(current.timmer){
clearTimeout(current.timmer)
}
//重新赋值计时器,并在计时结束后执行回调函数
current.timmer = setTimeout(() => {
f.apply(useDebounce,args)
}, delay);
}
}

这里我将防抖函数写成了一个自定义的hook,也是写的第一个hook,调用时需要传入两个参数,第一个参数是需要进行防抖处理的函数,第二个参数是防抖的延时时间,hook返回值是经过防抖处理的函数。

二、解决回调函数中获取不到最新state值的问题

在实现获取评论列表时,我希望每次只获取一定数量的评论,当用户浏览到页面底端时再获取新的评论,在实现过程中我用到了intersectionObserverAPI,并在它的回调函数中引用了组件中的一些state。

当我直接在useEffect副作用函数中进行绑定监听的元素时,发现回调函数中的state值一直保持observer对象创建时的值,经过查询相关资料,得知这可能是因为闭包的影响。解决办法是使用useRef创建一个对象用于保存observer对象,并在相关state值发生变化后释放原来的observer对象,创建一个新的observer对象,并重新绑定要监听的元素。

//指向要监听的元素
const bref = useRef(null)
//保存observer对象
const observer = useRef<any>() //每当comments变化,都会重新创建一个observer对象,其回调函数中引用的就是最新的state值
useEffect(() => {
let c = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio > 0) {
if (page * pageNum <= count) {
const fd = new FormData()
fd.append('articleId', param.articleid)
fd.append('page', page + 1)
fd.append('pageNum', pageNum)
http({ url: '/comment/comments', options: { method: 'POST', body: fd } }).then(res => {
if (count !== res.count) {
setcount(res.res.count)
} setpage(page + 1)
setcomments([...comments, ...res.res.rows])
})
} }
})
//取消旧的监听
if (observer.current) {
observer.current.unobserve(bref.current)
}
//保存新的observer对象,并建立新的监听
observer.current = c
observer.current.observe(bref.current)
}, [comments])



实践出真知,在项目中发现问题,寻找解决问题的方法,大江不止兮水长流,不断积累,丰富阅历,提升能力。

react中useRef的应用的更多相关文章

  1. React 中阻止事件冒泡的问题

    在正式开始前,先来看看 JS 中事件的触发与事件处理器的执行. JS 中事件的监听与处理 事件捕获与冒泡 DOM 事件会先后经历 捕获 与 冒泡 两个阶段.捕获即事件沿着 DOM 树由上往下传递,到达 ...

  2. 在React中使用 react-router-dom 编程式路由导航的正确姿势【含V5.x、V6.x】

    ## react-router-dom 编程式路由导航 (v5) ###### 1.push跳转+携带params参数 ```jsx props.history.push(`/b/child1/${i ...

  3. React中实现keepalive组件缓存效果

    背景:由于react官方并没有提供缓存组件相关的api(类似vue中的keepalive),在某些场景,会使得页面交互性变的很差,比如在有搜索条件的表格页面,点击某一条数据跳转到详情页面,再返回表格页 ...

  4. 理解React中es6方法创建组件的this

    首发于:https://mingjiezhang.github.io/(转载请说明此出处). 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的 ...

  5. 【原】React中,map出来的元素添加事件无法使用

    在使用react中,经常用到react的map函数,用法和jquery里中的map一样,但是,如果你在每个map出来的元素中添加,你会发觉添加的事件无法关联, 比如,我们很多的评论,我需要在每个评论下 ...

  6. React中props.children和React.Children的区别

    在React中,当涉及组件嵌套,在父组件中使用props.children把所有子组件显示出来.如下: function ParentComponent(props){ return ( <di ...

  7. Immutable 详解及 React 中实践

    本文转自:https://github.com/camsong/blog/issues/3 Shared mutable state is the root of all evil(共享的可变状态是万 ...

  8. React中父组件与子组件之间的数据传递和标准化的思考

    React中父组件与子组件之间的数据传递的的实现大家都可以轻易做到,但对比很多人的实现方法,总是会有或多或少的差异.在一个团队中,这种实现的差异体现了每个人各自的理解的不同,但是反过来思考,一个团队用 ...

  9. React中使用CSSTransitionGroup插件实现轮播图

    动画效果,是一个页面上必不可少的功能,学习一个新的东西,当然就要学习,如何用新的东西,用它的方法去实现以前的东西啦.今天呢,我就在这里介绍一个试用react-addons-css-transition ...

  10. 在React中使用Redux

    这是Webpack+React系列配置过程记录的第六篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...

随机推荐

  1. 一文带你吃透Redis

    目录 1. 基本数据结构 2. 数据持久化 3. 高可用 4. 缓存 文章字数大约1.9万字,阅读大概需要66分钟,建议收藏后慢慢阅读!!! 1. 基本数据结构 什么是Redis Redis是一个数据 ...

  2. MD5 简介 以及 C# 和 js 实现【加密知多少系列】

    〇.简介 MD5 是哈希算法(散列算法)的一种应用.Hash 算法虽然被称为算法,但实际上它更像是一种思想.Hash 算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是 Hash 算法. 算 ...

  3. 【经验分享】RTC 技术系列之视频编解码

    要了解什么是视频编解码,首先我们需要了解什么是视频. 视频归根结底是一系列连续的图像帧,当这些图像以一定速率播放时,人眼就会判断其是连续活动的,这样就构成了视频. 那为什么要进行视频编解码呢,因为视频 ...

  4. Trie(字典)树模板

    模板 int son[N][26], cnt[N], idx; // 0号点既是根节点,又是空节点 // son[][]存储树中每个节点的子节点 // cnt[]存储以每个节点结尾的单词数量 // 插 ...

  5. 页面div垂直内容超出后,edge浏览器右侧没有自动出现滚动条

    搜索网上解决办法,是给父元素添加样式 overflow-y:scroll; height:100vh; 但此举只是给该父元素侧边添加滚动条,而且不好配合回到顶部这一效果 最后发现是在父组件的包裹元素中 ...

  6. TCP三次握手,四次分手。个人感觉最容易理解的解释

    三次握手 名词解释 SYN,ACK,FIN存放在TCP的标志位,一共有6个字符,这里就介绍这三个: SYN:代表请求创建连接,所以在三次握手中前两次要SYN=1,表示这两次用于建立连接,至于第三次什么 ...

  7. go微服务框架kratos学习笔记三(构建单独的http或者grpc demo项目)

    go微服务框架kratos学习笔记三(构建单独的http或者grpc demo项目) 前面两篇跑通了demo项目,和大概了解了kratos demo整体结构,本篇分别构建一个http和一个grpc微服 ...

  8. [网络/Linux]处理安全报告/安全漏洞的一般流程与思路

    对近期工作中所经历的4次处理第三方网络安全公司的安全报告及其安全漏洞的经验做一点小结. 1 流程 Stage1 阅读/整理/分类:安全漏洞报告的安全漏洞 (目的:快速了解漏洞规模和分布) Stage2 ...

  9. [Windows/Linux]Linux下的正斜杠"/"和"\"的区别 [转载]

    执行某一条Linux命令时,遇到了此问题,甚为不解.[文由] 本篇属于全文转载自: Linux下的正斜杠"/"和""的区别 - 博客园 >>> ...

  10. Java设计模式 —— 外观模式

    13 外观模式 13.1 外观模式概述 Facade Pattern: 为子系统的接口提供一组统一的入口.外观模式定义了一个高层接口,这个接口使得子系统的更加容易使用. 在外观模式中,一个子系统的外部 ...