React组件化开发(6)- ref&受控与非受控组件(5)
11.ref
11.1什么是ref?
ref是一个特殊的属性,指向组件或者元素的一个引用,可以通过ref来获取到真实的组件或者一个DOM元素。
11.2使用ref
在React的开发模式中,通常情况不需要,也不建议直接操作DOM元素,但是某些特殊情况,确实需要获取到DOM进行某些操作:
- 管理焦点,文本选择或媒体播放
- 触发强制动画
- 集成第三方DOM库
如何创建refs来获取对应的DOM?目前有三种方式:
方式一:传入字符串
- 使用时通过this.refs.传入的字符串来拿到对应的元素
- 这个方式不推荐
方式二:传入对象
- 传入对象里面其实是一个函数:createRef,这个函数是React里面的跟Component一样。
- 然后React.createRef()赋给某个变量
- 这个变量就可以给到那个传入的对象里面
- 使用时通过this.那个变量.current 来拿到对应的元素
方式三:传入函数
- 这个函数其实有参数,创建一个变量把这个参数存到那个变量就可以了
- 使用时通过this.refs.变量 来拿到对应的元素
三种方式对应的例子:
import React, { createRef, PureComponent } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.TitleFnRef = null;
this.state = {
TitleRef: React.createRef()
}
}
render() {
return (
<div>
{/* 1.传入字符串 */}
<h2 ref="TitleRef">Hello Quan</h2>
{/* 2.传入对象 */}
<h2 ref={this.state.TitleRef}>Hello Quan</h2>
{/* 3.传入函数 */}
<h2 ref={arg => this.TitleFnRef = arg}>Hello Quan</h2>
<button onClick={e => this.ChangeText()}>切换文字</button>
</div>
)
}
ChangeText() {
// 1.传入字符串
this.refs.TitleRef.innerHTML = "Hello HTML";
// 2.传入对象
this.state.TitleRef.current.innerHTML = "Hello CSS";
// 3.传入函数
this.TitleFnRef.innerHTML = "Hello JavaScript"
}
}
11.3ref的类型
ref的值根据节点的类型而有所不同
- 当ref用于html元素中,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性
- 当ref用于一个类组件中,ref 对象接收组件的挂载实例作为其 current 属性;
不能再函数组件中使用ref,因为它没有实例
- 函数组件是没有实例的,所以无法通过ref获取它们的实例
- 但是某些时候,我们可能想要获取函数组件中的某个DOM元素
- 这个时候可以通过React.forWardRef(这是个高阶组件),后面再学习hooks中如何使用ref
演示ref用于类组件用:
这样就可以拿到组件对象里的一些数据,或者调用里面的一些函数。
import React, { createRef, PureComponent } from 'react'
class Footer extends PureComponent {
render() {
return (
<div>
<h2>哈哈</h2>
</div>
)
}
}
export default class App extends PureComponent {
constructor() {
super();
this.ClassRefVal = React.createRef();
}
render() {
return (
<div>
<Footer ref={this.ClassRefVal} />
</div>
)
}
ChangeText() {
console.log(this.ClassRefVal.current); // 得到的时Footer组件对象
}
}
12.受控组件和非受控组件
12.1受控组件
在React中,HTML表单的处理方式和普通的DOM元素不太一样:表单元素通常会保存在一些内部的state。
比如下面的HTML表单元素:
- 这个处理方式是DOM默认处理HTML表单的行为,在用户点击提交时会提交到某个服务器中,并且刷新页面
- 在React中,并没有禁止这个行为,它依然是有效的
- 但是通常情况下会使用JavaScript函数来方便的处理表单提交,同时还可以访问用户填写的表单数据
- 实现这种效果的标准方式是使用“受控组件”;
简单理解就是我们可以控制的表单数据称为受控组件,如果表单数据不是交给React来管理的,而是通过ref来从DOM节点来获取表单数据称为非受控组件。
受控组件演练
在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。
而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。
- 我们将两者结合起来,使React的state成为“唯一数据源”;
- 渲染表单的 React 组件还控制着用户输入过程中表单发生的操作;
- 被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”
import React, { PureComponent } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.state = {
user: ''
}
}
render() {
return (
<div>
<form onSubmit={e => this.handleSubmit(e)}>
<label htmlFor='user'>
用户名:<input type="text" id="user" value={this.state.user} onChange={e => this.handleUser(e)}></input>
</label>
<input type="submit"></input>
</form>
</div>
)
}
handleUser(e) {
this.setState({
user: e.target.value
})
}
handleSubmit(e) {
// 取消默认事件
e.preventDefault();
console.log(this.state.user);
}
}
- 由于在表单元素上设置了 value 属性,因此显示的值将始终为 this.state.value,这使得 React 的 state 成为唯一数据源
- 由于 handleUser在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新
受控组件-处理多输入
import React, { PureComponent } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.state = {
user: "",
password: "",
vaild: ""
}
}
render() {
return (
<div>
<form onSubmit={e => this.handleSubmit(e)}>
<label htmlFor="user">
用户名:<input type="text" name="user" id="user" onChange={e => this.handleData(e)}></input>
</label>
<label htmlFor="password">
密码<input type="text" name="password" id="password" onChange={e => this.handleData(e)}></input>
</label>
<label htmlFor="vaild">
验证码<input type="text" name="vaild" id="vaild" onChange={e => this.handleData(e)}></input>
</label>
</form>
</div>
)
}
handleSubmit(e) {
e.preventDefault();
}
handleData(e) {
this.setState({
// es6的语法:计算属性名
[e.target.name]: e.target.value
})
}
}
12.2非受控组件
React推荐大多数情况下使用 受控组件 来处理表单数据:
- 一个受控组件中,表单数据是由 React 组件来管理的;
- 另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理;
如果要使用非受控组件中的数据,那么我们需要使用 ref 来从DOM节点中获取表单数据。
非受控组件演练
import React, { PureComponent, createRef } from 'react'
export default class App extends PureComponent {
constructor() {
super();
this.inputRef = createRef();
}
render() {
return (
<div>
<form onSubmit={e => this.handleSubmit(e)}>
<label htmlFor='user'>
用户名:<input type="text" id="user" ref={this.inputRef} onChange={e => this.handleUser(e)}></input>
</label>
<input type="submit"></input>
</form>
</div>
)
}
handleUser(e) {
console.log(this.inputRef.current.value);
}
handleSubmit(e) {
e.preventDefault();
console.log(this.inputRef.current.value);
}
}
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭