React 中的转发ref

2018-08-06  本文已影响772人  JamesSawyer

React V16.3� 中react引入了:

这2个APIs,这对父组件中访问子组件中DOM元素提供了极大的便利

普通的使用

在当前组件中使用ref

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // create a ref to store the textInput DOM element
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // Explicitly focus the text input using the raw DOM API
    // Note: we're accessing "current" to get the DOM node
    this.textInput.current.focus();
  }

  render() {
    // tell React that we want to associate the <input> ref
    // with the `textInput` that we created in the constructor
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

通过回调函数的形式将ref传递给子组件中的DOM中

回调refs

function Child(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  
  componentDidMount() {
    if (this.textInputRef) this.textInputRef.focus();
  }

  render() {
    return (
      <Child inputRef={el => this.textInputRef = el}
    );
  }
}

将ref从父组件中转发到子组件中的dom元素上

// FancyButton.js 子组件
import React from 'react';

// 接受props和ref作为参数
// 返回一个React 组件
const FancyButton = React.forwardRef((props, ref) => (
    <button class="fancybutton" ref={ref}>
    {props.children}
  </button>
));

export default FancyButton;


// 父组件
// app.js
class App extends React.Component {
  
  constructor(props) {
    super(props);
    // 创建一个ref 名字随意
    this.fancyButtonRef = React.createRef();
  }
  
  componentDidMount() {
    console.log('ref', this.ref);
    // this.ref.current 表示获取ref指向的DOM元素
    this.ref.current.classList.add('primary'); // 给FancyButton中的button添加一个class
    this.ref.current.focus(); // focus到button元素上
  }
  
  render() {
    // 直接使用ref={this.fancyButtonRef}
    return (
        <FancyButton ref={this.fancyButtonRef}>子组件</FancyButton>
    );
  }
}

在高阶组件中使用转发ref

如果使用了高阶组件,还是按照上面普通的方式使用的话,会导致ref直接转发到高阶组件上,这很明显是错的,我们只需转发多次即可

// 高阶组件
import React from 'react';

function logProps(Component) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('先前的属性:', prevProps);
      console.log('当前属性:', this.props);
    }
    
    render() {
      // 使用forwardedRef作为一个ref属性传入组件中
      const { forwardedRef, ...rest } = this.props;
      return (
        <Component ref={forwardedRef} {...rest} />
      );
    }
  }
  
  // 使用React.forwardRef对LogProps组件进行转发
  return React.forwardRef((props, ref) => (
    {' 上面定义的LogProps组件接受一个forwarded属性 '}
    <LogProps forwardedRef={ref} {...props} />
  ));
}



// FancyButton.js 子组件
import React from 'react';
import logProps from './logProps';

// 接受props和ref作为参数
// 返回一个React 组件
const FancyButton = React.forwardRef((props, ref) => (
    <button class="fancybutton" ref={ref}>
    {props.children}
  </button>
));

// 使用高阶组件对其进行封装
export default logProps(FancyButton);


// 父组件
// app.js
class App extends React.Component {
  
  constructor(props) {
    super(props);
    // 创建一个ref 名字随意
    this.fancyButtonRef = React.createRef();
  }
  
  componentDidMount() {
    console.log('ref', this.ref);
    // this.ref.current 表示获取ref指向的DOM元素
    this.ref.current.classList.add('primary'); // 给FancyButton中的button添加一个class
    this.ref.current.focus(); // focus到button元素上
  }
  
  render() {
    // 直接使用ref={this.fancyButtonRef}
    return (
        <FancyButton ref={this.fancyButtonRef}>子组件</FancyButton>
    );
  }
}

可以看出如果需要使用高阶组件,则在高阶组件中也需要对其进行转发。

上一篇下一篇

猜你喜欢

热点阅读