【06】基础知识:React组件实例三大核心属性 - ref

一、 ref 了解

理解

组件内的标签可以定义 ref 属性来标识自己

使用

1、字符串形式的 ref

复制代码
定义:<input ref="input"/>
获取:this.refs.input

2、回调形式的 ref

复制代码
定义:<input ref={currentNode => this.input = currentNode} />
定义简写:<input ref={c => this.input = c} />
获取DOM元素:this.input

3、createRef创建 ref 容器

复制代码
创建容器:myRef = React.createRef() 
绑定:<input ref={this.myRef}/>
获取:this.myRef.current

二、案例

需求:自定义组件, 功能说明如下

点击按钮,提示第一个输入框中的值

当第2个输入框失去焦点时,提示这个输入框中的值

1、字符串形式的 ref (过时,不推荐,存在一些效率问题)

通过 ref 给标签打标识,通过组件实例的 refs 属性获取对应的 DOM 元素

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>1_字符串形式的ref</title>
</head>
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		class Demo extends React.Component {
			render() {
				return (
					<div>
						<input ref="input1" type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={this.showData}>点我提示左侧的数据</button>&nbsp;
						<input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
					</div>
				)
			}

			// 展示左侧输入框的数据
			showData = () => {
				const { input1 } = this.refs
				alert(input1.value)
			}

			// 展示右侧输入框数据
			showData2 = () => {
				alert(this.refs.input2.value)
			}
		}

		ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
	</script>
</body>
</html>

2、回调函数形式的ref

拿到当前 ref 所在的节点,React 调用回调函数,传入节点,挂载在实例自身,赋值给 input1

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_回调函数形式的ref</title>
</head>
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		class Demo extends React.Component {
			render() {
				return (
					<div>
						<input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={this.showData}>点我提示左侧的数据</button>&nbsp;
						<input ref={c => this.input2 = c} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />&nbsp;
					</div>
				)
			}

			// 展示左侧输入框的数据
			showData = () => {
				const { input1 } = this
				alert(input1.value)
			}
			// 展示右侧输入框的数据
			showData2 = () => {
				alert(this.input2.value)
			}
		}

		ReactDOM.render(<Demo />, document.getElementById('test'))
	</script>
</body>
</html>

3、回调ref中回调执行次数的问题

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会执行两次,第一次传入参数null,然后第二次会传入参数 DOM 元素。

这是因为在每次渲染是会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。

通过将 ref 的回调函数定成 class 的绑定函数的方式可以避免上述问题,但大多数情况下它是无关紧要的。

内联函数方式定义(推荐,写法简单):

执行 1+n*2 次,初次渲染和更新时执行(第一次null,第二次DOM元素),不会产生什么问题。

绑定函数形式:

执行1次,初次渲染时执行。

jsx 中写注释:{/* ... */}

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>3_回调ref中回调执行次数的问题</title>
</head>
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	
	<script type="text/babel">
		class Demo extends React.Component {
			state = { isHot: false }
			render() {
				return (
					<div>
						{/* <input ref={c => { this.input = c; console.log('@', c) }} type="text" /> */}
						<input ref={this.saveInput} type="text" />
						<button onClick={this.showData}>点我提示内容</button><br />

						<h2>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
						<button onClick={this.changeWeather}>点我切换天气</button>
					</div>
				)
			}

			showData = () => {
				alert(this.input.value)
			}

			changeWeather = () => {
				this.setState({
					isHot: !this.state.isHot
				})
			}

			saveInput = c => {
				this.input = c
				console.log('@', c) // 初次渲染时执行1次
			}
		}

		ReactDOM.render(<Demo />, document.getElementById('test'))
	</script>
</body>
</html>

4、createRef的使用

React.createRef 调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点,该容器是【专人专用】的。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>4_createRef的使用</title>
</head>
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		class Demo extends React.Component {
			myRef = React.createRef()
			myRef2 = React.createRef()

			showData = () => {
				// console.log(this.myRef) // 通过current取DOM元素
				alert(this.myRef.current.value)
			}

			showData2 = () => {
				alert(this.myRef2.current.value)
			}

			render() {
				return (
					<div>
						<input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />&nbsp;
						<button onClick={this.showData}>点我提示左侧的数据</button>&nbsp;
						<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据" />&nbsp;
					</div>
				)
			}
		}

		ReactDOM.render(<Demo />, document.getElementById('test'))
	</script>
</body>
</html>
相关推荐
whysqwhw几秒前
Kuikly 扩展原生 API 的完整流程
前端
whysqwhw2 分钟前
Hippy 跨平台框架扩展原生自定义组件
前端
OEC小胖胖5 分钟前
页面间的导航:`<Link>` 组件和 `useRouter`
前端·前端框架·web·next.js
faimi40 分钟前
🚀程序员必收藏!最全Git命令手册:解决90%团队协作难题
前端·gitlab
coooliang1 小时前
【鸿蒙 NEXT】V1迁移V2状态管理
java·前端·harmonyos
程序员码歌1 小时前
零代码AI编程实战-热搜从0到1技术方案
前端·ai编程·cursor
kk不中嘞2 小时前
浅谈前端框架
前端·vue.js·react.js·前端框架
服务端技术栈2 小时前
历时 1 个多月,我的第一个微信小程序「图片转 Excel」终于上线了!
前端·后端·微信小程序
一个很老的小萌新2 小时前
json 解析 [{“id“:1,“name“:“apple“},{“id“:2,“name“:“banana“}]
java·前端·json
yanlele2 小时前
前端面试第 78 期 - 2025.09.07 更新 Nginx 专题面试总结(12 道题)
前端·javascript·面试