React ref以及withRef的使用

情景描述

  • 将一个form表单封装成了一个组件并且使用antd的Form.create()将组件包裹起来(Form)

  • 将触发表单提交的button单独封装成了另外一个组件 (Button)

  • 他们都在一个父组件中的render函数中

  • Button点击之后必须触发父组件主动去获取Form组件中的数值

  • 目标

    • 可以在点击Button的时候push父组件主动的去获取Form组件中每个input中的内容然后提交
  • 问题

    • Button组件被点击之后如何提醒父组件去取值
    • 父组件如何取到Form组件中的值
    • 每一个组件的this对象中都有一个refs,可以拿到组件中所有加了ref的组件,为什么Form组件没有这个refs key?

问题

  • Q1:Button组件被点击之后如何提醒父组件去取值?
  • A1:子组件给父组件数据的方式:
    • 1.回调函数的方式:父组件给子组件传递setState方法子组件调用去修改值。
      • 局限:父组件想要获取值必须有事件能够触发子组件调用父组件传递过来的方法
    • 2.利用ref:给子组件加一个ref,然后任何父组件想要获取子组件内容的时候都可以通过调用ref获取到子组件然后直接利用ref调用子组件中的方法即可
      • 通常不推荐使用ref的方式去获取某个组件内部的props值或者state值,这样会破坏组件的封装性。
      • 我们通常使用ref去调用组件中的某个方法

因此要解决这个问题很容易:直接将父组件获取Form内容的函数直接传递给子组件,然后一旦子组件被click直接调用

  • Q2:父组件使用ref获取到的子组件中有什么呢?
  • A2: 通过ref可以拿到当前的React组件的引用(请注意这说明的是React组件的引用,并不是DOM元素)
    • context
    • 还有通过ref回调函数赋值的数据
    • props、state
    • 还有组件内部所有方法
    • refs:就是使用ref=字符串的方式添加的组件引用都在这个对象中

  • Q3:首先我们使用ref给Form中的每一个input加上了ref回调函数,按照正常情况通过给Form加上ref,这时候ref对象中必然有每个input的数据,问题是使用了connect包裹的Form组件没有办法获取Form组件内部每个input中的数据,这是为什么呢?
  • A3:原因很简单,使用了connect或者Form.create他们都是高阶组件,就是通过传入一个组件进入函数,然后返回另外一个组件,必然导致组件的引用内容发生变化。使用connect之后ref对象中就会包含所有connect给他添加的方法。唯一保留下来REACT组件中的内容就是props和state还有refs(但是refs中的数据始终为空了)并且组件中的方法也都不存在了,导致没有办法拿到被connect包裹的Form组件input中的数据了。

  • Q4:如果Form组件被高阶组件包裹,那么该如何获取被包裹的组件的原生ref呢?
  • A4:通过给Form组件的connect加上第四个参数{withRef:true}就可以将connect中被包裹的组件的refs保留下来。

  • Q5:那么使用{withRef:true}将被包裹的React组件ref保留下来之后如何在父组件中拿到ref呢?
  • A5:首先获取到connect返回的高阶组件
    • 高阶组件的ref中有一个getWrappedInstance方法
    • 这个方法被调用之后就会返回被包裹组件的ref
    • 从而拿到被包裹组件中input的值

你可能感兴趣的:(React ref以及withRef的使用)