[React] ref属性

简介

ref 即 reference ,是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。
组件被调用时会新建一个该组件的实例,而 ref 就会指向这个实例。它可以是一个回调函数,这个回调函数会在组件被挂载后立即执行。
为了防止内存泄漏,当卸载一个组件的时候,组件里所有的 ref 都会变为 null。

目录

  • 简介
  • ref的创建
    • 类组件
    • 函数组件
  • ref作为属性
    • 类组件
      • ref属性是一个字符串(已废弃,不建议使用)
      • ref 属性是一个函数
      • ref属性是一个ref对象
    • 函数组件
  • ref作用
    • 受控组件与非受控组件
      • 受控组件
      • 非受控组件
    • useRef

ref的创建

所谓 ref 对象的创建,就是通过 React.createRef 或者 React.useRef 来在组件中创建一个 ref 原始对象,用来获取dom元素。

{current:null , // current指向ref对象获取到的实际内容,可以是dom元素,组件实例,或者其它。
}

类组件

在类组件上通过createRef创建ref对象。

class Test extends React.Component{constructor(props){super(props);this.currentRef = React.createRef(null);}componentDidMount(){console.log(this.currentRef);}render= () => <div ref={ this.currentRef } >createRef test</div>
}
export default Test;

在这里插入图片描述

createRef 就是创建了一个对象,对象上的 current 属性,用于保存通过 ref 获取的 DOM 元素,组件实例等。

// react/src/ReactCreateRef.js
export function createRef() {const refObject = {current: null,}return refObject;
}

createRef 一般用于类组件创建 ref 对象,可以将 ref 对象绑定在类组件实例上,这样更方便后续操作 ref
注意:不要在函数组件中使用 createRef,否则会造成 ref 对象内容丢失等情况。

函数组件

在函数组件中通过 useRef 来创建 ref 对象。

export default function Test() {const currentRef = React.useRef(null)React.useEffect(() => {console.log(currentRef.current)}, []);return <div ref={ currentRef } >useRef test</div>
}

在这里插入图片描述

useRef 底层逻辑是和 createRef 差不多,就是 ref 保存位置不相同。类组件有一个实例 instance 能够维护像 ref 这种信息,所以createRef是直接把ref对象存储在 instance 上的,而函数组件没有这种instance,如果在函数组件上使用createRef,那么每一次函数组件更新,所有变量都会重新声明,那么ref就会随之被重置,起不到保存的效果了,这就是函数组件为什么不能用 createRef 的原因。
为了解决这个问题,hooks 和函数组件对应的 fiber 对象建立起关联,将 useRef 产生的 ref 对象挂到函数组件对应的 fiber 上,函数组件每次执行,只要组件不被销毁,函数组件对应的 fiber 对象一直存在,所以 ref 等信息就会被保存下来。

ref作为属性

react 对 ref 的处理,主要表现在父子组件交互时,处理标签中的 ref 属性,以及转发 ref

类组件

ref属性是一个字符串(已废弃,不建议使用)

在类组件中,用字符串 ref 标记一个 DOM 元素或一个类组件,在react 在底层逻辑会判断类型,如果是 DOM 元素,会把真实 DOM 绑定在组件 this.refs (组件实例下的 refs )属性上,如果是类组件,会把子组件的实例绑定在 this.refs 上。

class Children extends React.Component {render = () => <div>hello,world</div>
}export default class Test extends React.Component {componentDidMount() {console.log(this.refs) // }render = () => <div><div ref="currentDom">ref是字符串</div><Children ref="currentComInstance" /></div>
}

在这里插入图片描述
上述代码中,取值时可以用this.ref.currentDomthis.ref.currentComInstance取到相应的元素。
这种方式已经废弃了,原因有以下几点:

  1. string ref 不可组合,如果第三方库的父组件已经给子组件传递了 ref,那么我们就无法再在子组件上添加 ref
  2. 回调引用没有一个所有者,因此您可以随时编写它们
  3. 不适用于Flow之类的静态分析
  4. string ref 强制React跟踪当前正在执行的组件

ref 属性是一个函数

class Children extends React.Component {render = () => <div>hello,world</div>
}export default class Test extends React.Component {currentDom = nullcurrentComponentInstance = nullcomponentDidMount() {console.log(this.currentDom)console.log(this.currentComponentInstance)}render = () => <div><div ref={(node) => this.currentDom = node}  >ref是函数</div><Children ref={(node) => this.currentComponentInstance = node} /></div>
}

在这里插入图片描述
如上述代码所示,当用一个函数来标记 ref 的时候,将作为 callback 形式,等到真实 DOM 创建阶段,执行 callback ,获取的 DOM 元素或组件实例,再以回调函数第一个参数形式返回。所以可以像所以在上述代码中,用组件实例下的属性 currentDomcurrentComponentInstance 来接收真实 DOM 和组件实例。

ref属性是一个ref对象

创建ref对象,如第一部分所述,使用createRef

class Children extends React.Component {render = () => <div>hello,world</div>
}
export default class Test extends React.Component {currentDom = React.createRef(null)currentComponentInstance = React.createRef(null)componentDidMount() {console.log(this.currentDom)console.log(this.currentComponentInstance)}render = () => <div><div ref={this.currentDom}>ref是对象</div><Children ref={this.currentComponentInstance} /></div>
}

打印
以上三种方法都无法用在函数组件中,因为函数组件没有实例。

函数组件

不能在函数组件上直接使用 ref 属性,因为他们没有实例,这时需要用到forwardRef

import React, { useEffect, useRef } from 'react';const Child = React.forwardRef((props, ref) => {return <input ref={ref}></input>
})const Test = () => {const childrenRef = useRef();useEffect(() => {console.log(childrenRef.current); // child input}, [])return <Child ref={childrenRef}></Child>
}
export default Test;

在这里插入图片描述
React.forwardRef返回的是一个react组件,接受的参数是一个render函数,render(props, ref)。这个函数的第二个参数会将接收到的ref作为返回组件的ref属性,这就实现了ref的转发。

ref作用

其实ref是不推荐使用的,因为使用ref后,一些情况下元素会脱离react的控制。

受控组件与非受控组件

受控组件

受控组件指的是,在表单控件(例如input等),其值是受到react管理和控制的,即仅需要定义一个state和setState函数,在用户输入时UI和值都可以实时更新。

import React, { useState } from 'react';function ControlledComponentExample() {const [inputValue, setInputValue] = useState('');const handleInputChange = (event) => {setInputValue(event.target.value);};return (<div><label htmlFor="input">Enter something: </label><inputtype="text"id="input"value={inputValue}onChange={handleInputChange}/><p>You typed: {inputValue}</p></div>);
}

上述代码流程为,当input中值发生改变时,触发handleInputChange函数,从而将event.target.value更新到inputValue上,state的更新触发了页面的重新渲染,所以页面也更新了。
受控组件的特点时,数据流是单向的,均由state变化而触发,所以不应该强制赋值。

非受控组件

非受控组件即通过ref直接取dom元素中的值,而不是通过state控制它。

import React, { useRef } from 'react';function UncontrolledComponentExample() {const inputRef = useRef(null);const handleButtonClick = () => {alert('Input value is: ' + inputRef.current.value);};return (<div><label htmlFor="uncontrolledInput">Enter something: </label><inputtype="text"id="uncontrolledInput"ref={inputRef}/><button onClick={handleButtonClick}>Get Input Value</button></div>);
}

点击按钮的时候,handleButtonClick函数中直接通过ref拿取input中的值,不通过react自身的state变换。

useRef

在函数组件中,useRef 返回一个可变的 ref 对象,返回的 ref 对象在函数组件的整个生命周期内保持不变。所以 useRef 可以很方便地保存任何可变值。

import { useState, useEffect, useRef } from "react";export default function Test() {const ref = useRef(false)const [a, setA] = useState(0);useEffect(() => {if (!ref.current) {ref.current = true} else {//do some}}, [a]);return ('');
}

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

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

相关文章

【Java多线程案例】单例模式

1. 单例模式概念 设计模式&#xff1a;谈到单例模式&#xff0c;我们首先需要知道什么是设计模式&#xff0c;设计模式是软件工程中的一大重要概念&#xff0c;是被广泛认可并使用于解决特定实际问题的代码设计经验&#xff0c;校招中常考的设计模式有单例模式、工厂模式 等&a…

python的数据类型

&#x1f388;srting&#xff08;字符串&#xff09;&#xff1a; 操作符&#xff1a; &#xff1a;字符串连接 aabc befg print(ab) #输出 abcdefg * : 重复输出字符串 aabc print(a*3) #输出 abcabcabc [ : ]:截取字符串中的一部分&#xff0c;遵循左闭右开的原则&am…

李宏毅LLM——大模型+大资料的神奇力量

文章目录 大模型的重要性顿悟时刻 大资料的重要性数据预处理不一样的做法&#xff1a;KNN LM 对应视频P12-P14 大模型的重要性 模型参数和数据集越大&#xff0c;文字接龙的错误率越低 顿悟时刻 当模型超过10B-20B时&#xff0c;会突然顿悟 启示&#xff1a;不能只看最终结…

黑马Java——集合进阶(List、Set、泛型、树)

一、集合的体系结构 1、单列集合&#xff08;Collection&#xff09; 二、Collection集合 1、Collection常见方法 1.1代码实现&#xff1a; import java.util.ArrayList; import java.util.Collection;public class A01_CollectionDemo1 {public static void main(String[] a…

寻迹模块——红外循迹模式使用介绍

目录 循迹模式——红外循迹模式使用介绍 红外循迹模块介绍 接线 循迹小车原理 安装与接线 实验程序 实验效果 循迹模式——红外循迹模式使用介绍 实验效果&#xff1a; 寻迹模块-CSDN直播 红外循迹模块介绍 传感器的红外发射二极管不断发射红外线&#xff0c;当发射出…

[C/C++] -- Boost库、Muduo库编译安装使用

1.Muduo库 Muduo 是一个基于 C11 的高性能网络库&#xff0c;其核心是事件驱动、非阻塞 I/O、线程池等技术&#xff0c;以实现高并发、高性能的网络通信。Muduo 库主要由陈硕先生开发维护&#xff0c;已经成为 C 服务器程序员的常用工具之一。 Muduo 库的主要特点&#xff1a…

前端工程化之:webpack2-2(内置插件)

目录 一、内置插件 1.DefinePlugin 2.BannerPlugin 3.ProvidePlugin 一、内置插件 所有的 webpack 内置插件都作为 webpack 的静态属性存在的&#xff0c;使用下面的方式即可创建一个插件对象&#xff1a; const webpack require("webpack")new webpack.插件…

Web3智能合约:重新定义商业合作的未来

随着区块链技术的飞速发展&#xff0c;Web3时代正逐渐到来&#xff0c;而其中的智能合约成为推动商业合作变革的关键力量。本文将深入探讨Web3智能合约的概念、特点以及对商业合作未来的巨大影响。 什么是Web3智能合约&#xff1f; 智能合约是一种以代码形式编写、自动执行合同…

React+Echarts实现数据排名+自动滚动+Y轴自定义toolTip文字提示

1、效果 2、环境准备 1、react18 2、antd 4 3、代码实现 原理&#xff1a;自动滚动通过创建定时器动态更新echar的dataZoom属性startValue、endValue&#xff0c;自定义tooltip通过监听echar的鼠标移入移出事件&#xff0c;判断tooltTip元素的显隐以及位置。 1、导入所需组…

【考研数学】选汤家凤1800 还是 张宇1000❓关键看这一点

考研备考&#xff0c;如果没有准备好&#xff0c;真的不要随便开始&#xff0c;因为已经有人开始后悔了&#xff01; 特别是关于考研数学&#xff0c;很多人都不知道该如何刷题&#xff0c;如何选资料&#xff0c;下面我就分享一下我的经验&#xff1a; 关于考研做题&#xf…

RobotFramework报错都是因为什么

1、参数问题FAILKeyword common. Bpm Ui Query Delete Data expected 44 arguments,got 3. 这种报错的意思是&#xff0c;应该有4个参数&#xff0c;实际只展示了3个参数 找对应的解决方案一 可能是入参的时候数量不一致 解决方案二&#xff1a; 对应的参数中间有空格 …

机器学习 | 一文看懂SVM算法从原理到实现全解析

目录 初识SVM算法 SVM算法原理 SVM损失函数 SVM的核方法 数字识别器(实操) 初识SVM算法 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种经典的监督学习算法&#xff0c;用于解决二分类和多分类问题。其核心思想是通过在特征空间中找到一…