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);
  }
}
文章目录