封装个组件怎么连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 应用的开发效率和代码质量。

相关推荐
前端小巷子5 分钟前
前端工程化——Webpack
前端·javascript·面试
结城12 分钟前
聊聊原生 CSS 变量:让样式更灵活的“魔法”
前端·css
小屁孩大帅-杨一凡15 分钟前
如何使用markdownify库将HTML转换为Markdown?
开发语言·前端·python·html
啃火龙果的兔子3 小时前
修改 Lucide-React 图标样式的方法
前端·react.js·前端框架
前端 贾公子3 小时前
为何在 Vue 的 v-model 指令中不能使用可选链(Optional Chaining)?
前端·javascript·vue.js
潘多拉的面3 小时前
Vue的ubus emit/on使用
前端·javascript·vue.js
遗憾随她而去.3 小时前
js面试题 高频(1-11题)
开发语言·前端·javascript
hqxstudying6 小时前
J2EE模式---前端控制器模式
java·前端·设计模式·java-ee·状态模式·代码规范·前端控制器模式
开开心心就好7 小时前
Excel数据合并工具:零门槛快速整理
运维·服务器·前端·智能手机·pdf·bash·excel
im_AMBER7 小时前
Web开发 05
前端·javascript·react.js