React组件三大核心属性3: refs

理解:组件内的标签可以定义ref属性来标识自己(可联想到标签内的id属性)

1、三种不同形式的ref

(1)字符串形式的ref(不推荐使用)

<input ref="input1" />
    class Demo extends React.Component{
      showData = () => {
        console.log(this)
        console.log(this.refs.input1)
        console.log(this.refs.input1.value)
      }
      render() {
        return (
        	<div>
          	<input ref="input1" type="text" placeholder="请输入内容"	/>
            <button onClick={this.showData}>点击提示输入的内容</button>
          </div>
        )
      }
    }

当点击按钮后,调用showData函数,由于该函数是箭头函数,所以this指的就是该Demo组件的实例对象,console.log(this)会使得控制台输出这个实例对象,该实例对象的身上会有很多内容,如propsstatecontextshowData函数等,当然也有refs

如果给input标签指定一个ref属性,如ref='input1',那么在该实例对象的身上,refs里就会有{input1: input}这个对象,它的key就是我们当初指定的input1,value就是input这个标签节点(真实DOM节点)。那么,我们就可以用this.refs.input1来获取这个标签节点,而this.refs.input1.value就能获取到我们输入的值。

字符串形式ref存在一些效率上的问题,是过时的api,可能会在未来版本被移除。官网不推荐使用。

(2)回调形式的ref

<input ref={c => this.input1 = c}/>
class Demo extends React.Component{
      showData = () => {
        console.log(this)
        console.log(this.input1)
        console.log(this.input1.value)
      }
      render() {
        return (
        	<div>
          	<input ref={currentNode => this.input1 = currentNode} type="text" placeholder="请输入内容"	/>
            <button onClick={this.showData}>点击提示输入的内容</button>
          </div>
        )
      }
    }

input标签内加上ref={currentNode => this.input1 = currentNode}后,在执行代码的时候,react会帮我们调用这个回调函数并执行,那么,在实例对象自身的refs属性内就会有{input1: input}这个对象了。

ref属性内的回调函数做的事就是:把当前所处的input节点(currentNode)赋值给Demo实例自身,并起名为input1,此处的this就是实例对象自身。那我们在用的时候就只要this.input1就能拿到这个input节点了

ref内回调函数的执行次数问题:如果ref回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数null,然后第二次会传入参数DOM元素。这是因为在每次渲染时会创建一个新的函数实例,所以React清空旧的ref并且设置新的。通过将ref的回调函数定义成class的绑定函数的方式(如下代码块所示)可以避免上述问题,但是大多数情况下它是无关紧要的。

class Demo extends React.Component{
      showData = () => {
        console.log(this)
        console.log(this.input1)
        console.log(this.input1.value)
      }
      saveInput = () => {
        this.input1 = c
        console.log('saveInput()', c)
      }
      render() {
        return (
        	<div>
          	<input ref={this.saveInput} type="text" placeholder="请输入内容"	/>
            <button onClick={this.showData}>点击提示输入的内容</button>
          </div>
        )
      }
    }

(3)createRef创建ref容器

myRef=React.createRef()
<input ref={this.myRef}/>
class Demo extends React.Component{
      myRef = React.createRef()
      showData = () => {
        console.log(this.myRef)
        console.log(this.myRef.current)
        console.log(this.myRef.current.value)
      }
      render() {
        return (
        	<div>
          	<input ref={this.myRef} type="text" placeholder="请输入内容"	/>
            <button onClick={this.showData}>点击提示输入的内容</button>
          </div>
        )
      }
    }

React.createRef()调用后可以返回一个容器,该容器可以存储被ref所标识的节点。我们把节点放在了myRef这个变量中。当我们在input节点内加上ref={this.myRef}后,执行代码的时候就会把ref所在的当前节点直接存储到了myRef这个容器中。当我们在控制台输出this.myRef时,显示的是{current: input},因此,我们可以用this.myRef.current来拿到这个input节点了。如果要获取用户在该节点输入的值,只要this.myRef.current.value就可以了。

需要注意的是,一个容器只能存储一个节点,后放进去的就会替代前面放进去的内容。

此外,最近遇到一种使用createRef创建ref容器的用法:即,如何做到父组件调用子组件对象的方法。

class ProductAddUpdate extends Component {
      constructor(props) {
        super(props)
        //创建用来保存ref标识的标签对象的容器
        this.pw = React.createRef()
      }
      submit = () => {
        //进行表单验证,如果都通过了,才发送请求
        this.props.form.validateFields((err, values) => {
          if (!err) {
            //表单验证通过,可以发起ajax请求了
            console.log("表单验证通过!", values);
            const imgs = this.pw.current.getImgs()
            console.log('imgs', imgs)
          } else {
            message.error("表单验证不通过!");
          }
        });
      };
      render(){
        return (
        	<Card>
          	<Form>
            	<Form.Item>
              	<PicturesWall ref={this.pw} imgs={imgs}/>
              </Form.Item>
              <Form.Item>
                <Button type="primary" onClick={this.submit}>
                  提交
                </Button>
              </Form.Item>
            </Form>
          </Card>
        )
      }
    }
export default class PicturesWall extends Component {
      getImgs = () => {
        return this.state.fileList.map(file => file.name);
      };
      render(){
        return (
        	......
        )
      }
    }

父组件ProductAddUpdate需要调用子组件<PictureWall />内的方法getImgs():首先,一般在构造器内创建ref容器: this.pw = React.createRef();其次,将ref容器交给需要获取的标签元素: <PicturesWall ref={this.pw} />,它会自动将标签对象(<PictureWall />)添加为pw容器对象的current属性,注意,标签对象就是组件对象;最后,通过ref容器读取标签对象: this.pw.current。那么,我们就可以通过const imgs = this.pw.current.getImgs()来获取到子组件内的图片名称数组了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值