Antd踩坑 — 当子组件是 function component 时使用 wrappedComponentRef

7,681 阅读2分钟

问题起源

父组件想拿到子组件的 ref,使用 antd 的 Form.create() 包装子组件之后,可以通过包装后的组件的 wrappedComponentRef 拿到子组件的实例。但是因为子组件是一个 function component 没有实例,导致不能在子组件上使用 wrappedComponentRef 属性(本质上使用了 ref 属性获得子组件的实例 _class,且 antd 对本来的 ref 属性另外包装了一下,返回的不是子组件的实例 _class)。

解决办法

使用回调函数拿到子组件的 this,或者将函数式组件转化为一个 class

  • 一个子组件是 class 的🌰:
class CollectionCreateForm extends React.Component {
    render() {
      const { visible } = this.props;
      return (
        <Modal visible={visible}>
          <span> hello </span>
        </Modal>
      );
    }
}

export default class App extends React.Component {
  state = {
    visible: false,
  };
  showModal = () => {
    this.setState({ visible: true });
  };
  saveFormRef = formRef => {
    this.formRef = formRef;
    console.log(this.formRef, "我要输出")
  };

  render() {
    return (
      <div>
        <Button type="primary" onClick={this.showModal}>
          New Collection
        </Button>
        <CollectionCreateForm
          ref = {this.saveFormRef}
          visible = {this.state.visible}
        />
      </div>
    );
  }
}

  • 一个子组件是 function Component 的🌰:
// 子组件改一下就行
function CollectionCreateForm(props){
  const { visible } = props;
    return(
        <Modal visible={visible}>
          <span> hello </span>
        </Modal>
      )
}

注意了我们虽然拿不到子组件实例,但是可以拿到子组件中 DOM refs。

不管怎样,你可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件

父子组件 ref 传递

那么如果想在父组件中拿到函数式组件里面的 DOM refs 应该怎么做呢?

  1. ref 转发:使用 React.forwardRef 函数包装一下 function component

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

React.forwardRef((prop,ref)=>{function component})

eg:

import React, {forwardRef} from 'react';

function ThisWontWork() {
  return <button>Text</button>;
}

const ThisWillWork = forwardRef((props, ref) => { // React 传递 ref 给 forwardRef 内函数 (props, ref) => ...,作为其第二个参数。
  return <button ref={ref}>Text</button>;// 下发 ref 参数,并将其指定给 button 的JSX属性
});

function App() {
const childRef = React.createRef(); 
console.log(childRef) // {current:<button></button>}
  return (
    <Tippy content="Tooltip">
        // 拿到子组件的 ref 
      <ThisWillWork ref={childRef}/>
    </Tippy>
  );
}
  1. 使用自定义属性,在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件。
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} /> // 取 props 里面的属性
    </div>
  );
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.inputElement = React.createRef();
  }
  render() {
    return (
      <CustomTextInput inputRef={this.inputElement} />
    );
  }
}

3.自己封装一个函数传递到子组件里面去,拿到子组件的 this 或者某个元素的 refs 不使用回调函数的方式:

// 父组件中
<childCom childRef={ refs =>{ this.refs = refs}}>...</childCom> 
// 子组件中
<childCom>
    <div ref={props.childRef}>hello</div>
</childCom>