封装个组件怎么连ref都拿不到?React你礼貌吗?

React.forwardRef

在 React 的组件化开发中,forward是一个非常重要且实用的 API,它主要用于解决高阶组件(HOC)或其他组件包装方式中,原始组件的属性和引用传递问题。

一、React.forwardRef的基本概念

在正常情况下,ref属性不能像普通属性一样通过组件传递,因为ref并不是组件 props 的一部分。而React.forwardRef则打破了这一限制,让组件可以将ref转发给内部的某个子元素。React.forwardRef是 React 提供的一个函数,它允许组件接收并向子组件传递ref。

其基本语法如下:

jsx 复制代码
const ForwardedComponent = React.forwardRef((props, ref) => {
  return <div ref={ref} {...props} />;
});

const App(){
    const myRef = useRef(null)
    return (
        <ForwardedComponent ref={myRef}/>
    )
}

这里,使用forwardRef接收一个渲染函数,该函数接收props和ref两个参数,并返回一个 React 元素。通过这种方式,当外部组件使用ForwardedComponent并传递ref时,这个ref会被传递到内部的div元素上。

二、React.forwardRef的实现原理

从本质上来说,React.forwardRef创建了一个特殊的组件类型。当 React 渲染这种组件时,会将ref作为第二个参数传递给渲染函数,而不是像普通组件那样忽略ref。

在 React 内部,组件会被分为不同的类型,forwardRef创建的组件会被标记为一种特殊的类型。当处理这种类型的组件时,React 会知道要将ref传递给渲染函数,而不是将其作为普通的ref附加到组件实例上(对于类组件)或忽略(对于函数组件)。

三、React.forwardRef的使用场景

  1. 高阶组件(HOC)中转发 ref

    高阶组件是 React 中复用组件逻辑的一种方式,但它可能会导致ref传递出现问题。例如,当我们创建一个 HOC 来包装组件时,外部传递给 HOC 的ref会指向 HOC 本身 ,而不是被包装的原始组件。这时,使用 React.forwardRef 可以将 ref 转发到原始组件上。

    jsx 复制代码
    function withLogging(MyComponent) {
      const ComponentWithLogging = React.forwardRef((props, ref) => {
        console.log('Component rendered');
        return <MyComponent ref={ref} {...props} />;
      });
      return ComponentWithLogging;
    }
    
    const MyComponent = (props) => <div {...props} />;
    // 使用withLogging 包裹 MyComponent 形成 MyComponentWithLogging
    const MyComponentWithLogging = withLogging(MyComponent);
    
    // 使用时,ref会指向MyComponent内部的元素
    const ref = React.createRef();
    <MyComponentWithLogging ref={ref} />;
  2. 在 UI 组件库中使用

    在开发 UI 组件库时,很多组件是由多个基础元素组合而成的。为了让使用者能够方便地获取到组件内部的某个关键元素(如输入框、按钮等),组件库的开发者可以使用 React.forwardRef 将 ref 转发到对应的内部元素上。

    例如,一个自定义的输入框组件:

    jsx 复制代码
    const CustomInput = React.forwardRef((props, ref) => {
      return (
        <div className="custom-input">
          <input ref={ref} {...props} />
        </div>
      );
    });

    使用者在使用CustomInput时,可以像使用普通input一样获取ref,从而操作输入框元素。

  3. 与其他 React 特性结合使用

    React.forwardRef 还可以与其他 React 特性(如useImperativeHandle)结合使用,自定义暴露给父组件的实例值。useImperativeHandle可以让组件指定通过ref 暴露给父组件的方法和属性,而React.forwardRef则负责将ref传递进来。

    jsx 复制代码
    const CustomComponent = React.forwardRef((props, ref) => {
      const [value, setValue] = React.useState('');
    
      React.useImperativeHandle(ref, () => ({
        focus: () => {
          // 执行聚焦操作
        },
        getValue: () => value
      }));
    
      return <input value={value} onChange={(e) => setValue(e.target.value)} />;
    });

    这样,父组件通过ref可以调用focus方法和getValue方法,而不是直接获取input元素。

四、使用React.forwardRef的注意事项

  1. 只在函数组件中使用

    React.forwardRef的渲染函数是一个函数组件,它不能是类组件。如果需要在类组件中使用类似的功能,可以通过其他方式(如将ref作为普通 props 传递,命名为innerRef等)来实现。

  2. 避免过度使用

    虽然React.forwardRef很有用,但也不要过度使用。在大多数情况下,通过 props 传递数据和回调函数已经足够满足需求。只有当确实需要获取组件内部元素的引用时,才考虑使用React.forwardRef。

  3. 类型定义(TypeScript)

    在使用 TypeScript 开发时,需要为forwardRef创建的组件正确定义类型,以确保类型安全。可以使用ForwardedRef和ComponentPropsWithoutRef等类型工具来辅助定义。

    jsx 复制代码
    import React, { forwardRef, ForwardedRef } from 'react';
    
    interface CustomInputProps {
      label: string;
    }
    
    const CustomInput = forwardRef((props: CustomInputProps, ref: ForwardedRef<HTMLInputElement>) => {
      return (
        <div>
          <label>{props.label}</label>
          <input ref={ref} />
        </div>
      );
    });

五、总结

React.forwardRef是 React 中一个非常实用的 API,它解决了ref在组件层级中传递的问题,使得高阶组件、UI 组件库等场景下的开发更加便捷。通过理解其基本概念、使用场景和工作原理,并注意使用过程中的一些细节,可以更好地发挥它的作用,提高 React 应用的开发效率和代码质量。

相关推荐
架构技术专栏1 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
别动我齐刘海2 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
志尊宝2 小时前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
刘发财3 小时前
前端如何生成10000页PDF文件?
前端·javascript·开源
A接拉起0074 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
用户11481867894844 小时前
面试官:大屏项目里十几个模块同时渲染上万条数据,怎么做到不卡?
前端·性能优化
前端市界4 小时前
Pro React Admin: 统一工程底座,承载多种应用...
前端·github
葡萄城技术团队4 小时前
dsh-spreadjs-editor 当前支持什么:安装前需要了解的几件事
前端
三*一4 小时前
优化修整算法
前端·javascript·算法
weifont5 小时前
自动化抓取和上架商品:能不动手,就少动手
运维·前端·自动化