React 中 ref 的使用

69 阅读2分钟

ref 是一个入口 允许您直接访问DOM元素或组件实例。

使用ref的三大原则:

1.可以在dom元素上面使用ref属性

2.可以在class组件上面使用ref属性

3.不准在函数组件上面使用ref属性,原因:函数组件没有实例,父组件获取子组件的ref,其实是在获取子组件的实例;但是可以在函数组件中 获取子组件实例的ref,并用一个变量存储起来,这个是没有问题的

代码描述 ref 的使用
import React, {Component, Fragment} from 'react'

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: ''
    }
    this.inputChange = this.inputChange.bind(this)
  }

  render() {
    return (
      <Fragment>
        <div>
          {/* 
              箭头函数构建一个 ref
              箭头函数会自动的接收一个参数,参数的名字可以随便取 (input)
              this.input = input 这句话的意思是 指向input Dom节点
              ref={(input) => {this.input = input}}
          */}
          <input
            value={this.state.inputValue}
            onChange={this.inputChange}
            ref={(input) => {this.input = input}}/>
        </div>
      </Fragment>
    )
  }

  inputChange(e) {
    console.log(this.input.value)  //通过Dom获取 (ref)
    console.log(e.target.value)    //通过数据形式
  }
}

export default TodoList;

不推荐用ref,React建议我们数据驱动形式来编写代码尽量不要直接操作Dom,如果用ref有的时候会遇到各种各样的问题。举例:

import React, {Component, Fragment} from 'react'
import TodoItem from "./TodoItem";

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: '',
      list: ['星期一', '星期二', '星期三']
    }
    this.inputChange = this.inputChange.bind(this)
    this.setInputChange = this.setInputChange.bind(this)
    this.delListItem = this.delListItem.bind(this)
  }

  render() {
    return (
      <Fragment>
        <div>
          <input
            value={this.state.inputValue}
            onChange={this.inputChange}
            ref={(input) => {
              this.input = input
            }}/>
          <button onClick={this.setInputChange}>提交</button>
        </div>
        <ul ref={(ul) => {this.ul = ul}}>
          {this.getTodoItem()}
        </ul>
      </Fragment>
    )
  }

  getTodoItem() {
    return this.state.list.map((item, index) => {
      return (
        <TodoItem
          key={index}
          content={item}
          index={index}
          deleteItem={this.delListItem}
        />
      )
    });
  }

  inputChange(e) {
    const value = e.target.value
    this.setState(() => ({
      inputValue: value
    }));
  }

  setInputChange() {
    /* this.setState((prevState) => ({
     *   list: [...prevState.list, prevState.inputValue],
     *   inputValue: ''
     * }));
     * console.log(this.ul.querySelectorAll('li').length) 
     * 打印值是错误的。你获取的长度永远会比实际长度少一个
     * 上方的 querySelectorAll 是react提供给我的一个方法可以获取ul下的内容
     */

    /* 错误原因
     * setState是异步函数也就是说setState还没被执行已经执行console
     * 下方是解决方法
     */
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: ''
    }), () => {
      console.log(this.ul.querySelectorAll('li').length)
    });
  }

  delListItem(index) {
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
      return {
        list
      }
    });
  }
}

export default TodoList;