_React「 Refs 转发 」初探

栏目: IOS · Android · 发布时间: 4年前

内容简介:Refs 转发:将父组件创建的 ref 传递给子组件的某个dom元素(或组件)。让父组件可以直接操作该dom元素(或组件)一开始使用该技术的时候,分不清 传 自定义 ref prop 和 转发ref 有什么区别,本文稍微探讨下InputChild 为子组件,App 为父组件

前言

Refs 转发:将父组件创建的 ref 传递给子组件的某个dom元素(或组件)。让父组件可以直接操作该dom元素(或组件)

一开始使用该技术的时候,分不清 传 自定义 ref prop 和 转发ref 有什么区别,本文稍微探讨下

Demo: 父组件触发子组件的input元素获取焦点

InputChild 为子组件,App 为父组件

const InputChild = (props) => (
  <input></input>
));
class App extends React.Component {
  constructor() {
    super()
    this.icRef = React.createRef();
  }
  render () {
    <InputChild ref={this.icRef}>Click me!</InputChild>;
  }
}

按上面的操作,icRef 拿到的是 InputChild 组件,拿不到 InputChild 下的 input 元素。

比如想在父组件上让 InputChild 的 input 获取焦点,是不行的。

this.icRef.current.focus() //报错

InputChild 创建 ref 绑定 input

在 InputChild 上,利用 inputRef = React.createRef() 绑定 input,

然后父组件通过 ref.current.inputRef.current.focus() 获取焦点

class InputChild extends React.Component{
  constructor(){
    super()
    this.inputRef = React.createRef()
  }
  render(){
    return (
      <input ref={this.inputRef}></input>
    )
  } 
}
class App extends React.Component {
  constructor() {
    super()
    this.icRef = React.createRef();
  }
  render () {
    <InputChild ref={this.icRef}>Click me!</InputChild>;
  }
}
this.ref.current.inputRef.current.focus() // input 获取焦点

Refs 转发

函数组件使用

const InputChild = React.forwardRef((props, ref) => (
  <input ref={ref}>
  </input>
));
class App extends React.Component {
  constructor() {
    super()
    this.icRef = React.createRef();
  }
  handleClick = () => {
    this.icRef.current.focus()
  }
  render () {
     <>
      <button onClick={this.handleClick}>Learn React</button>
      <InputChild ref={this.icRef}>Click me!</InputChild>;
     </>
  }
}

点击 button 后,input 可以获取到焦点

Class 组件使用

function refProps(Component) {
  return React.forwardRef((props, ref) => {
    return <Component {...props} forwardedRef={ref} />;
  });
}

@refProps
class InputChild extends React.Component{
  render(){
    const { forwardedRef } = this.props;
    return (
      <input ref={forwardedRef}></input>
    )
  }
}

效果同上,但是这里是 将 ref 绑定到新的prop上

尚未知道还有没有更好的做法

自定义 prop 属性

其实也可以直接定义一个 非ref 的prop,如下

class InputChild extends React.Component{
  render(){
    const { forwardedRef } = this.props;
    return (
      <input ref={forwardedRef}></input>
    )
  }
}
// 父组件使用
<InputChild forwardRef={this.ref} />

注意:函数式组件不能提供ref,否则对ref的访问将会失败,只能用 React.forwardRef() 传递 ref

效果是一样,但是对于上层使用者(不知道子组件代码的)来说, 第一想法是用 ref 绑定子组件而不是其他额外prop (forwardRef)

高阶组件上使用 refs 转发

需求:我们有一个 LogProps 高阶组件用于记录 props log,但是对 上层用户是不可见的

用户使用 <Child ref={this.ref}/> 。 ref 拿到的应该是 Child 而不是 高阶组件

错误使用

function logProps(WrappedComponent) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  return LogProps;
}

@logProps
class Child extends React.Component{
  render(){
    <div/>
  }
}
<Child ref={this.ref}>Click me!</Child>;

this.ref 拿到的是 LogProps 组件,ref prop被消化,不会被传递到 Child

正确使用

function logProps(WrappedComponent) {
  class LogProps extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('old props:', prevProps);
      console.log('new props:', this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;

      // Assign the custom prop "forwardedRef" as a ref
      return <WrappedComponent ref={forwardedRef} {...rest} />;
    }
  }

  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}
@logProps
class Child extends React.Component{
  render(){
    <div/>
  }
}
<Child ref={this.ref}>Click me!</Child>;

this.ref 拿到的是 Child 组件

Child 组件使用高阶组件,并且父组件的 ref 要绑定 Child下的 input元素

在以上的基础上,再转发一次

const InputChild = React.forwardRef((props, ref) => (
  <input ref={ref}>
  </input>
));

// 使用高阶组件对其进行封装
export default logProps(InputChild);
// 父组件中
<Child ref={this.ref}>Click me!</Child>;

父组件 this.ref.current.focus() 即可让 input 获取焦点


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

别怕,Excel VBA其实很简单

别怕,Excel VBA其实很简单

Excel之家 (Excel Home) / 人民邮电出版社 / 2012-10-1 / 49.00元

《别怕,excel vba其实很简单》考虑到大多数读者没有编程基础的实际情况,用浅显易懂的语言和生动形象的比喻,并配合大量插画,介绍excel中看似复杂的概念和代码、从简单的宏录制、vba编程环境和基础语法的介绍,到常用对象的操作与控制、excel事件的调用与控制、用户界面设计、代码调试与优化、都进行了形象的介绍。 《别怕,excel vba其实很简单》适合想提高工作效率的办公人员,特别是经......一起来看看 《别怕,Excel VBA其实很简单》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具