React(五)useEffect、useRef、useImperativeHandle、useLayoutEffect

(一)useEffect

useEffect – React 中文文档

useEffect hook用于模拟以前的class组件的生命周期,但比原本的生命周期有着更强大的功能

1.类组件的生命周期

在类组件编程时,网络请求,订阅等操作都是在生命周期中完成

import React, { Component } from 'react'

export default class App extends Component {
  // 组件挂载后执行
  componentDidMount(){
    // 发送请求
    // 事件总线绑定
    // 创建定时器等
  }
  // 组件更新后执行
  componentDidUpdate(){

  }
  // 组件销毁前执行
  componentWillUnmount(){
    // 事件总线解绑
    // 清除定时器
  }

  render() {
    return (
      <div>App</div>

2.函数式组件的生命周期

函数式组件没有明确的生命周期,使用useEffect来模拟生命周期

useEffect(setup, dependencies?)

在useRffect的第一个参数传入回调函数,执行请求、挂载等操作

useEffect会在组件每次挂载、更新后调用回调 

import { useState, useEffect } from 'react'
function App() {
  const [count, setCount] = useState(0)

  useEffect(()=>{
    // 发送请求
    // store仓库订阅subscribe
    // 事件总线绑定 eventbus.on
    // 操作外部dom
    document.title = count
  })

  return (
    <>
      <div>{count}</div>
      <button onClick={()=>{setCount(count+1)}}>加1</button>
    </>
  )
}

如何在组件销毁前取消订阅或者移除绑定?

只需要在第一个回调里返回一个回调函数即可,useEffect会在组件销毁前/组件更新前调用

useEffect(()=>{
    // 发送请求
    // store仓库订阅subscribe
    // 事件总线绑定 eventbus.on
    // 操作外部dom
    document.title = count
    // 计数器
    const time = setInterval(()=>{
      console.log(1);
    },1000)

    return ()=>{
      // store仓库取消订阅 unsubscribe
      // 清除事件总线
      // 清除计数器等操作
      clearInterval(time)
    }
  })

回调函数内的代码太长了

拆分useEffect,每个功能都可以单独写一个useEffect,react会自动处理

  useEffect(()=>{
    // 发送请求
  })
  useEffect(()=>{
    // store仓库订阅subscribe
    return ()=>{
      // store仓库取消订阅 unsubscribe
    }
  })
  useEffect(()=>{
    // 计数器
    const time = setInterval(()=>{
      console.log(count);
    },1000)

    return ()=>{
      // 清除计数器等操作
      clearInterval(time)
    }
  })

执行次数会不会太多了?

向上面那样书写的话,每次update都会执行回调,更新一次dom就请求一次、绑定一次事件这样子也太蠢了,因此useEffect可以传入第二个参数,用来控制依据什么来决定是否执行,和之前useCallback、useMemo一样,都会传入dependencies这个参数

  // 只执行一次
  useEffect(()=>{
    // 发送请求
  },[])
  // 只执行一次
  useEffect(()=>{
    // store仓库订阅subscribe
    return ()=>{
      // store仓库取消订阅 unsubscribe
    }
  },[])
  // count改变才执行
  useEffect(()=>{
    document.title = count
  },[count])

useEffect先简单写到这里,useEffect虽然是模拟生命周期,但它能做的事比生命周期更多,能够根据传入的数组参数判断是否执行 

(二)useRef

useRef – React 中文文档

useRef 是一个 React Hook,它能帮助引用一个不需要渲染的值

useRef(initialValue)

initialValue:ref 对象的 current 属性的初始值。可以是任意类型的值。这个参数在首次渲染后被忽略 

useRef hook主要有两个功能:

  • 绑定dom元素
  • 保存一个数据,在整个生命周期中可以保存不变 

1.绑定dom元素

初始化const xxx = useRef();通过ref={xxx}来绑定ref

import { useState, useRef } from 'react'
function App() {
  const [count, setCount] = useState(0)

  const nameRef = useRef()
  console.log(nameRef.current);

  return (
    <>
      <div ref={nameRef}>csq</div>
      <div>{count}</div>
      <button onClick={()=>{setCount(count+1)}}>加1</button>
    </>
  )
}

通过xxx.current获取该dom元素

2.绑定一个值(解决闭包陷阱)

先说说闭包陷阱

闭包陷阱是指使用react hooks的时候,由于闭包特性,在某些函数内获取useState或者props的值时获取到的是旧的值,而实际值已经改变

使用 ref 可以确保:

  • 可以在重新渲染之间 存储信息(普通对象存储的值每次渲染都会重置)。
  • 改变它 不会触发重新渲染(状态变量会触发重新渲染)。
  • 对于组件的每个副本而言,这些信息都是本地的(外部变量则是共享的)。

改变 ref 不会触发重新渲染,所以 ref 不适合用于存储期望显示在屏幕上的信息。如有需要,使用 state 代替。

将新增count的操作放到useCallback回调里,会导致读取到的count始终为0

const [count, setCount] = useState(0)

  const increment = useCallback(()=>{
    setCount(count+1) // set(0+1)
    console.log(count); // 0
  },[])

  return (
    <>
      <div>{count}</div>
      <button onClick={()=>increment()}>加1</button>
    </>
  )

因为useCallback传入的依赖为空,意味着increment函数只生成一次,只能读取到生成时count的状态,即0(我感觉我也是蒙的)

这样就形成了闭包陷阱

解决办法:

(1)添加useCallback的依赖即可

const increment = useCallback(()=>{
    setCount(count+1) 
    console.log(count)
  },[count])

(2)使用useRef

const [count, setCount] = useState(0)
  const countRef = useRef()
  // count改变会引起重新渲染,这样countRef的值每次都和count相等
  countRef.current = count

  const increment = useCallback(()=>{
    setCount(countRef.current+1) 
  },[])

  return (
    <>
      <div>{count}</div>
      <button onClick={()=>increment()}>加1</button>
    </>
  )

这里肯定不是应用useRef的最好场景,毕竟加个依赖项就解决了

但使用useRef的话,increment函数就不会重新加载了!

(三)useImperativeHandle

useImperativeHandle – React 中文文档

useImperativeHandle 是 React 中的一个 Hook,它能让你自定义由 ref 暴露出来的句柄。

useImperativeHandle(ref, createHandle, dependencies?)

1.在父组件使用子组件的ref 

子组件获取父组件ref的方法:forwardRef()

forwardRef – React 中文文档

import { useRef, memo, forwardRef, useImperativeHandle } from 'react'
function App() {
  const childrenRef = useRef()
  const getDom = ()=>{
    console.log(childrenRef.current);
  }
  return (
    <>
      <button onClick={getDom}>获取dom元素</button>
      <Children ref={childrenRef}></Children>
    </>
  )
}

const Children = memo(forwardRef(function(props,ref){

  return (
    <>
      <input type="text" ref={ref} />
    </>
  )
}))

2.通过useImperativeHandle hook控制子组件ref能暴露的部分

import { useRef, memo, forwardRef, useImperativeHandle } from 'react'
function App() {
  const childrenRef = useRef()
  const getDom = ()=>{
    console.log(childrenRef.current);
    childrenRef.current.set(100)
    childrenRef.current.focus()
  }
  return (
    <>
      <button onClick={getDom}>获取dom元素</button>
      <Children ref={childrenRef}></Children>
    </>
  )
}

const Children = memo(forwardRef(function(props,ref){
  const inputRef = useRef()
  useImperativeHandle(ref,()=>{
    // 返回对象 该对象就是父组件能操作的chilrenRef
    return {
      set(value){
        inputRef.current.value = value
      },
      focus(){
        inputRef.current.focus()
      },
    }
  })
  return (
    <>
      <input type="text" ref={inputRef}  />
    </>
  )
}))

 这个hook的使用不是很常见,只要了解就ok

(四)useLayoutEffect

useLayoutEffect – React 中文文档

useLayoutEffect 是 useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。

useLayoutEffect(setup, dependencies?)

useLayoutEffect和useEffect在各个方面都是相同的,只是执行的时期不同,useLayout会阻塞dom的更新。如果需要在dom更新前进行操作,使用useLayoutEffect

1.使用useEffect

function App() {
  const [count,setCount] = useState(0)
  // 可见count在点击重置之后会先闪回0再变为随机数
  useEffect(()=>{
    console.log('useEffect');
    if(count == 0){
      setCount(Math.random()+100)
    }
  })
  return (
    <>
      <h1>count:{count}</h1>
      <button onClick={()=>setCount(0)}>重置为0</button>
    </>
  )
}

2.使用useLayoutEffect

如果需要在dom渲染之前改变的需求就使用useLayoutEffect 

function App() {
  const [count,setCount] = useState(0)

  // 在dom重新渲染前就捕获count进行更新 不会出现闪动情况
  useLayoutEffect(()=>{
    console.log('useLayoutEffect');
    if(count == 0){
      setCount(Math.random()+100)
    }
  })
  return (
    <>
      <h1>count:{count}</h1>
      <button onClick={()=>setCount(0)}>重置为0</button>
    </>
  )
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二叉树练习题(2024/6/5)

1翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]…

空间不够用了怎么办

空间告急啊哥们 整理一下清理空间有用的一些blog吧。 【linux】公共服务器如何清理过多的.cache缓存 linux根目录空间不足&#xff0c;追加空间到根目录下 【linux】linux磁盘空间 目录查看清理 和 文件查看清理

windows系统 flutter 开发环境配置

1、管理员运行powershell&#xff0c;安装&#xff1a;Chocolatey 工具&#xff0c;粘贴复制运行下列脚本: Chocolatey 官方安装文档 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManage…

韩顺平0基础学Java——第17天

p342-373 上课的时候一部分在纸上写过了&#xff0c;就不在这里复盘了。 this可以调用本类的所有方法&#xff0c;super可以调用父类的非private方法 Test Demo Rose Jack John jack 重写equals方法&#xff1a; 15&#xff1a; 1.调用C的有参构造器 2.进入B的有参构造器…

数字化营销有哪些模式?企业采用数字营销方式有什么意义?

在当今快速发展的商业环境中&#xff0c;营销已经远远超越了传统的推广和销售概念&#xff0c;演变成一种复杂而全面的组织职能。随着信息技术的飞速发展&#xff0c;数字化营销应运而生&#xff0c;为企业与消费者之间的互动带来了革命性的改变。数字化营销不仅为企业提供了全…

Spark SQL - 操作数据帧

本教程将通过一个具体的案例来演示如何在Spark SQL中操作数据帧。我们将从获取学生数据帧开始&#xff0c;包括两种方法&#xff1a;一是由数据集转换而来&#xff0c;二是直接读取文件生成数据帧。然后&#xff0c;我们将对数据帧进行各种操作&#xff0c;如投影、过滤、统计和…

SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析

目录 SpringCache 缓存 环境配置 1&#xff09;依赖如下 2&#xff09;配置文件 3&#xff09;设置缓存的 value 序列化为 JSON 格式 4&#xff09;EnableCaching 实战开发 Cacheable CacheEvict CachePut Caching CacheConfig SpringCache 的优势和劣势 读操作…

【网络协议 | HTTP】HTTP总结与全梳理(一) —— HTTP协议超详细教程

&#x1f525;博客简介&#xff1a;开了几个专栏&#xff0c;针对 Linux 和 rtos 系统&#xff0c;嵌入式开发和音视频开发&#xff0c;结合多年工作经验&#xff0c;跟大家分享交流嵌入式软硬件技术、音视频技术的干货。   ✍️系列专栏&#xff1a;C/C、Linux、rtos、嵌入式…

nginx代理vue项目路由跳转刷新

常规代理 在我们日常开发中&#xff0c;前端部署到服务器&#xff0c;需要用到nginx部署&#xff0c;简单代理如下&#xff1a; #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid…

GPT革命:AI如何重塑我们的未来!

GPT革命&#xff1a;AI如何重塑我们的未来&#xff01; &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享…

并查集算法

目录 1.算法介绍 1.1什么是并查集呢&#xff0c;它又是用来干什么的呢&#xff1f; 1.2问题引入 2.算法解析 2.1初始化 2.2合并操作 2.3查找 路径压缩 2.4问题解决代码 3.变式突破 1.算法介绍 1.1什么是并查集呢&#xff0c;它又是用来干什么的呢&#xff1f; 逐字拆…

经典的泡泡龙游戏源码免费下载

源码介绍 HTML5泡泡龙冒险小游戏是一款休闲网页游戏&#xff0c;游戏玩法是玩家从下方中央的弹珠发射台射出彩珠&#xff0c;多于3个同色珠相连则会消失。 源码下载 经典的泡泡龙游戏源码免费下载

【Python绘画】画正方形简笔画

本文收录于 《一起学Python趣味编程》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、代码示例三、知识点梳理四、总结 一、前言 本文介绍如何使用Python的海龟画图工具turtle&#…

docker-compose入门级实战教程

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…

Flutter Bloc之简单记录

目录 0.库安装 1.插件和自动生成 2.状态的配置 1.初始化中&#xff1a; 2.赋值完成后&#xff1a; 3.如果出错&#xff1a; 3.事件的配置 1.定义一个读取事件 2.定义一个更改事件 4.Bloc的设置 5.Bloc的使用 1.BlocProvider 2.内部调用 参考文章进行类的配置 0.库…

【ARM Cache 系列文章 2.1 -- Cache PoP 及 PoDP 介绍】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 PoP 及 PoDPCache PoDPCache PoP应用和影响PoP 及 PoDP Cache PoDP 点对深度持久性(Point of Deep Persistence, PoDP)是内存系统中的一个点,在该点达到的任何写操作即使在系统供电…

跳跃游戏二

方法一&#xff1a;&#xff08;双指针法&#xff09;此题参考跳台阶问题&#xff0c;题目要求求到达最后一个点的最小跳跃次数&#xff0c;那么我们就可以从最后一个往前推&#xff0c;先看谁能离得最远&#xff0c;并且能跳到最后一个。假设i位置是离最后一个位置最远&#x…

网工内推 | 联通公司,云计算售前,AWS认证优先

01 联通数字科技有限公司 &#x1f537;招聘岗位&#xff1a;云计算售前工程师 &#x1f537;职责描述&#xff1a; 1.了解私有云&#xff0c;公有云&#xff0c;混合云等云计算技术知识&#xff0c;了解云计算行业现状及发展趋势。 2.承担区域项目售前工作支持&#xff0c;为…

Linux基础指令磁盘管理002

LVM&#xff08;Logical Volume Manager&#xff09;是Linux系统中一种灵活的磁盘管理和存储解决方案&#xff0c;它允许用户在物理卷&#xff08;Physical Volumes, PV&#xff09;上创建卷组&#xff08;Volume Groups, VG&#xff09;&#xff0c;然后在卷组上创建逻辑卷&am…

NSS题目练习7

[MoeCTF 2022]baby_file 打开看见一串源代码&#xff0c;需要get传参传入file 题目提示php伪协议 用dirsearch扫描发现flag.php 用php伪协议查看&#xff0c;回显一串base64编码 解码后得到flag [鹤城杯 2021]Middle magic 读取这两个文件 一个php正则表达式 补充&#xff1a…