首页 > 其他分享 >React(五)UseEffect、UseRef

React(五)UseEffect、UseRef

时间:2024-06-02 21:57:57浏览次数:25  
标签:count UseRef useEffect const useRef React 组件 return UseEffect

(一)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函数就不会重新加载了!

(三)总结

只能说是对useEffect相见恨晚,这个钩子好牛b

今天写的较为简略QAQ

标签:count,UseRef,useEffect,const,useRef,React,组件,return,UseEffect
From: https://blog.csdn.net/DogEgg_001/article/details/139393146

相关文章

  • react 怎样配置ant design Pro 路由?
    AntDesignPro是基于umi和dva的框架,umi已经预置了路由功能,只需要在config/router.config.js中添加路由信息即可。例如,假设你需要为HelloWorld组件创建一个路由,你可以将以下代码添加到config/router.config.js中:在menu.ts中设置菜单标题:exportdefault{'......
  • 【图解IO与Netty系列】Reactor模型
    Reactor模型Reactor模型简介三类事件与三类角色Reactor模型整体流程各种Reactor模型单Reactor单线程模型单Reactor多线程模型主从Reactor模型Reactor模型简介Reactor模型是服务器端用于处理高并发网络IO请求的编程模型,与传统的一请求一线程的同步式编程模型不同的......
  • ref和reaction的区别(以及TS中ref,computed函数会自动推断定义其泛型(一般不用自己动手))
    其次就是了解ref,reactive的区别。ref通过对象名.value来访问对象里的值,若对象里还有属性则访问其需要:对象名.value.属性名reactive则通过:对象名.属性名,来直接访问属性值其次,两者都是响应式对象。但如果对直接对reactive对象进行赋值,那么其会丢失响应性。代码示例如下:<scri......
  • 【React】实现一个基本的防抖函数
    函数防抖(debounce),就是指触发事件后,在n秒内函数只能执行一次,如果触发事件后在n秒内又触发了事件,则会重新计算函数延执行时间(在这里和函数节流区分一下,函数节流是在触发完事件之后的一段时间之内不能再次触发事件)。实现:1consttimer=useRef<any>(null)//react中可用方......
  • 【React】react函数式编程常用hooks讲解
    ReactHooks是React16.8版本引入的一项重要特性,它极大地简化和优化了函数组件的开发过程。React中常用的Hooks,包括useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useLayoutEffect等。这些Hooks涵盖了状态管理、副作用处理、性能......
  • 2024前端react面试题
    css相关1.单行文本溢出显示省略号设置什么属性{overflow:hidden,text-overflow:ellipsis,white-space:nowrap}2.简素述盒子模型Box-sizing:context-box(正常盒子),border-box(ie盒子)Content-box:盒子的大小=设置的width,height+border+padding+marginborder-box:盒子大小=设置......
  • 如何使用带有 typescript 的 playwright 查找 react 应用程序的 LCP?
    需要获取使用playwright和typescript的react应用程序的最大Contentful画面这是用于网络性能测试的,应该是精确的值我尝试了https://web.dev/articles/lcp#measure-lcp-in-javascript并使用Typescript实现了相同的功能但是我们需要知道,我们是否还有其他东西returnp......
  • React后台管理(十四)-- 完整示例页面构建教学
    文章目录前言一、组件源码+详细注释说明+技术分析二、效果展示总结前言经过了前面文章的学习,终于到最后一步了,那就是一个管理页面的构建,包括处理列表请求,搜索、重置和展开/收起等功能。结合之前封装的布局、功能相关组件,在本文只需要按需引入,统一了代码标准,减少重......
  • react+three.js导入外部gltf格式
    我把gltf文件放在了public/static下面了。其他地方还没适用。因为之前想导入obj一直没成功,就跟着官网和各种例子成功导入了gltf格式的然后其他的没啥。看代码吧。大部分我都写了备注components组件importReact,{useEffect,useRef}from"react";import*asTHREE......
  • React
    react依赖react-native移动端跨平台16.13.1版本react:核心代码react-dom:渲染在不同平台需要的核心代码babel:jsx转换react代码工具//crossorigin在控制台显示远程的错误信息<scriptsrc="https://unpkg.com/react@16/umd/react.development.js"crossorigin></scrip......