React Refs转发实现流程详解

 更新时间:2022年12月03日 10:50:44   作者:码农小菲  
Refs是一个 获取 DOM节点或React元素实例的工具,在React中Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素,这篇文章主要给大家介绍了关于React中refs的一些常见用法,需要的朋友可以参考下

Refs转发

概述

  • 将ref自动地通过组件传递到子组件的技巧
  • 父组件可以通过ref操作子组件,直接使用子组件的DOM

转发refs到DOM组件

渲染原生 DOM 元素 button 的 FancyButton 组件(子组件)

function FancyButton(props) {
  return (
    <button className="FancyButton">
      {props.children}
    </button>
  )
}

Ref 转发是一个可选特性,其允许某些组件接收 ref,并将其向下传递给子组件

//子组件
const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
))
//父组件
//可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
//这样,在父组件中可以直接使用DOM button

以下是对上述示例发生情况的逐步解释:

  • 通过调用 React.createRef 创建了一个 React ref 并将其赋值给 ref 变量
  • 指定 ref 为 JSX 属性,将其向下传递给 FancyButton React
  • 传递ref给forwardRef作为其第二个参数
  • 向下转发ref参数到button,并将其指定为JSX属性
  • 当ref挂载完成,ref.current将指向button DOM节点

组件库维护者的注意事项

当使用forwardRf时,应将其视为一个新的主版本

在高阶组件中转发refs

转发ref对高阶组件是很有用的,让我们从一个输出组件props到控制台的高阶组件为例

 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组件是一个高阶组件,props将会传递到其包裹的组件。这个高阶组件可以记录所有传递到fancyButton组件的props

class FancyButton extends React.Component {
     focus() {
       // ...
     }
     // ...
}
   // 我们导出 LogProps,而不是 FancyButton。
   // 虽然它也会渲染一个 FancyButton。
   export default logProps(FancyButton)

需要注意:refs 将不会透传下去。这是因为 ref 不是 prop 属性。就像 key 一样,其被 React 进行了特殊处理

如果对 HOC 添加 ref,该 ref 将引用最外层的容器组件,而不是被包裹的组件

意味着用于我们 FancyButton 组件的 refs 实际上将被挂载到 LogProps 组件

   import FancyButton from './FancyButton';
   const ref = React.createRef();
   // 我们导入的 FancyButton 组件是高阶组件(HOC)LogProps。
   // 尽管渲染结果将是一样的,
   // 但我们的 ref 将指向 LogProps 而不是内部的 FancyButton 组件!
   // 这意味着我们不能调用例如 ref.current.focus() 这样的方法
   <FancyButton
     label="Click Me"
     handleClick={handleClick}
     ref={ref}
   />;

解决办法:可以使用 React.forwardRef API 明确地将 refs 转发到内部的 FancyButton 组件。React.forwardRef 接受一个渲染函数,其接收 props 和 ref 参数并返回一个 React 节点

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

      // 将自定义的 prop 属性 “forwardedRef” 定义为 ref
      return <Component ref={forwardedRef} {...rest} />;
    }
  }
  // 注意 React.forwardRef 回调的第二个参数 “ref”。
  // 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
  // 然后它就可以被挂载到被 LogProps 包裹的子组件上。
  return React.forwardRef((props, ref) => {
    return <LogProps {...props} forwardedRef={ref} />;
  });
}

在 DevTools 中显示自定义名称

下面的组件将在DevTools中显示为“ForwardRef”

const WrappedComponent = React.forwardRef((props, ref) => {
  return <LogProps {...props} forwardedRef={ref} />;
})

如果命名了渲染函数,DevTools 也将包含其名称(例如 “ForwardRef(myFunction)”)

const WrappedComponent = React.forwardRef(
  function myFunction(props, ref) {
    return <LogProps {...props} forwardedRef={ref} />;
  }
)

设置函数的 displayName 属性来包含被包裹组件的名称

function logProps(Component) {
  class LogProps extends React.Component {
    // ...
  }
  function forwardRef(props, ref) {
    return <LogProps {...props} forwardedRef={ref} />;
  }
  // 在 DevTools 中为该组件提供一个更有用的显示名。
  // 例如 “ForwardRef(logProps(MyComponent))”
  const name = Component.displayName || Component.name;
  forwardRef.displayName = `logProps(${name})`;
  return React.forwardRef(forwardRef);
}

到此这篇关于React Refs转发实现流程详解的文章就介绍到这了,更多相关React Refs转发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈在react中如何实现扫码枪输入

    浅谈在react中如何实现扫码枪输入

    这篇文章主要介绍了浅谈在react中如何实现扫码枪输入,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • react中使用echarts,并实现tooltip循环轮播方式

    react中使用echarts,并实现tooltip循环轮播方式

    这篇文章主要介绍了react中使用echarts,并实现tooltip循环轮播方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 基于visual studio code + react 开发环境搭建过程

    基于visual studio code + react 开发环境搭建过程

    今天通过本文给大家分享基于visual studio code + react 开发环境搭建过程,本文给大家介绍的非常详细,包括react安装问题及安装 Debugger for Chrome的方法,需要的朋友跟随小编一起看看吧
    2021-07-07
  • react antd实现动态增减表单

    react antd实现动态增减表单

    antd是react流行的ui框架库,本文主要介绍了react antd实现动态增减表单,分享给大家,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • React-Hooks之useImperativeHandler使用介绍

    React-Hooks之useImperativeHandler使用介绍

    这篇文章主要为大家介绍了React-Hooks之useImperativeHandler使用介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • 详解React中函数式组件与类组件的不同

    详解React中函数式组件与类组件的不同

    React 函数式组件与类组件的主要区别在于它们的定义和声明方式以及它们之间的一些特性,所以本文就详细的给大家讲讲React中函数式组件与类组件有何不同,需要的朋友可以参考下
    2023-09-09
  • React组件设计模式之组合组件应用实例分析

    React组件设计模式之组合组件应用实例分析

    这篇文章主要介绍了React组件设计模式之组合组件,结合实例形式分析了React组件设计模式中组合组件相关概念、原理、应用场景与操作注意事项,需要的朋友可以参考下
    2020-04-04
  • react中使用forEach或map两种方式遍历数组

    react中使用forEach或map两种方式遍历数组

    这篇文章主要介绍了react中使用forEach或map两种方式遍历数组,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • react显示文件上传进度的示例

    react显示文件上传进度的示例

    这篇文章主要介绍了react显示文件上传进度的示例,帮助大家更好的理解和学习使用react,感兴趣的朋友可以了解下
    2021-04-04
  • 详解如何在Remix 中使用 tailwindcss

    详解如何在Remix 中使用 tailwindcss

    这篇文章主要为大家介绍了如何在Remix中使用tailwindcss方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05

最新评论