当前位置: 首页 > ai >正文

React 中二次封装组件时,实现 属性透传、事件透传、插槽透传和 ref 透传

在 React 中二次封装组件时,实现 属性透传、事件透传、插槽透传和 ref 透传 是常见的需求。以下是详细的解释和实现方法:

一、属性透传(Props Forwarding)
核心目标
将外层组件接收的 props 自动传递给内部组件,无需手动逐个声明。

实现方法
展开运算符直接透传
适用于不需要拦截或修改的 props:

jsx
const WrappedComponent = (props) => {// 添加自定义逻辑(可选)const customProps = { ...props, className: `custom-style ${props.className}` };return <OriginalComponent {...customProps} />;
};

过滤特定 props
当需要排除某些 props 时:

jsx
const { excludedProp, ...restProps } = props;
return <OriginalComponent {...restProps} />;
合并冲突 props
处理与内部组件冲突的 props:jsx
const mergedProps = { ...props,onClick: (e) => {props.onClick?.(e); // 调用外部传入的 onClickhandleInternalClick(e); // 添加内部逻辑}
};

二、事件透传(Event Forwarding)
核心目标
将内部组件的事件(如 onClick、onChange)暴露给外层组件。

实现方法
直接透传事件

jsx
const WrappedInput = (props) => {return <input {...props}onChange={(e) => {props.onChange?.(e); // 触发外层 onChange}}/>;
};

添加中间处理逻辑
例如节流或数据转换:

jsx
const ThrottledInput = (props) => {const handleChange = useThrottle((e) => {props.onChange?.(e.target.value);}, 300);return <input {...props} onChange={handleChange} />;
};

三、插槽透传(Slots Forwarding)
核心目标
将外层组件接收的 children 或其他插槽内容传递给内部组件。

实现方法
基础 children 透传

jsx
const Wrapper = ({ children }) => {return <div className="wrapper"><OriginalComponent>{children}</OriginalComponent></div>;
};

多插槽透传
通过命名 props 实现多个插槽:

jsx
const Layout = ({ header, footer, children }) => {return (<div><header>{header}</header><main>{children}</main><footer>{footer}</footer></div>);
};// 使用
<Layout header={<HeaderComponent />}footer={<FooterComponent />}
><MainContent />
</Layout>

动态插槽组合
通过 React.cloneElement 修改子元素:

jsx
const EnhancedList = ({ children }) => {return React.Children.map(children, (child) => {return React.cloneElement(child, {className: 'enhanced-item'});});
};

四、Ref 透传(Ref Forwarding)
核心目标
允许外层组件直接访问内部组件的 DOM 节点或组件实例。

实现方法

使用 forwardRefjsx
const WrappedInput = React.forwardRef((props, ref) => {return <input {...props} ref={ref} />;
});// 父组件使用
const App = () => {const inputRef = useRef();return <WrappedInput ref={inputRef} />;
};

透传类组件实例
如果内部是类组件:

jsx
class OriginalComponent extends React.Component { /* ... */ }const WrappedComponent = React.forwardRef((props, ref) => {return <OriginalComponent ref={ref} {...props} />;
});

暴露特定方法
使用 useImperativeHandle 控制暴露内容:

jsx
const WrappedInput = React.forwardRef((props, ref) => {const inputRef = useRef();useImperativeHandle(ref, () => ({focus: () => inputRef.current.focus(),getValue: () => inputRef.current.value}));return <input {...props} ref={inputRef} />;
});

五、综合封装示例
结合所有特性的完整封装:

jsx
const EnhancedButton = React.forwardRef((props, ref) => {const { children,className,onHover, // 自定义新增的 prop...restProps } = props;// 合并 classNameconst mergedClassName = `enhanced-btn ${className || ''}`;// 事件处理const handleMouseEnter = (e) => {props.onMouseEnter?.(e);onHover?.(true);};return (<button{...restProps}ref={ref}className={mergedClassName}onMouseEnter={handleMouseEnter}><span className="icon"></span>{children}</button>);
});// 使用
<EnhancedButton onClick={() => console.log('Clicked')}onHover={(isHovering) => console.log(isHovering)}ref={buttonRef}
>Submit
</EnhancedButton>

六、最佳实践
TypeScript 支持
使用泛型定义 Props 类型:

tsx
interface EnhancedButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {onHover?: (isHovering: boolean) => void;
}const EnhancedButton = React.forwardRef<HTMLButtonElement, EnhancedButtonProps>((props, ref) => { /* ... */ }
);

避免 Props 污染
通过过滤无关 props 防止传递给 DOM:

jsx
const { onHover, ...buttonProps } = props;
return <button {...buttonProps} />;

性能优化
使用 React.memo 避免不必要的渲染:

jsx
const MemoizedWrapper = React.memo(WrappedComponent);

通过以上方法,可以灵活地实现 React 组件的二次封装,同时保持对属性、事件、插槽和 ref 的完整控制。

以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!

http://www.xdnf.cn/news/4918.html

相关文章:

  • iOS App 安全性探索:源码保护、混淆方案与逆向防护日常
  • 互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现
  • 4.1【LLaMA-Factory 实战】医疗领域大模型:从数据到部署的全流程实践
  • clahe算法基本实现
  • Linux 环境通过 tar 多线程压缩和解压
  • 护城河理论——AI与思维模型【100】
  • 5级李克特量表:量化态度的黄金标准
  • 生信服务器如何安装cellranger|生信服务器安装软件|单细胞测序软件安装
  • ndarray数组掩码操作,True和False获取数据
  • vue3: pdf.js5.2.133 using typescript
  • Windows 10 无法启动或黑屏的修复指南(适用于更新失败或磁盘故障)
  • javascript 补充的一些知识点
  • HarmonyOS学习——ArkTS与TS的关系
  • ArcScroll: 弧形滑动控件
  • 初等数论--欧拉函数积性的证明
  • Uniapp Android/IOS 获取手机通讯录
  • 【Linux】自定义shell的编写
  • vllm的技术核心、安装流程和使用教程,以及注意事项
  • 自主独立思考,帮我创造新的方法:vue3 script setup语法中,组件传递值我觉得有些复杂,帮我创造一种简单的方法容易写的方法?
  • 使用Java实现HTTP协议服务:从自定义服务器到内置工具
  • 数据加密方式(对称加密/非对称加密 /数字签名/证书)
  • vue项目的创建
  • 字符串---Spring字符串基本处理
  • 耳机插进电脑只有一边有声音怎么办 解决方法分享
  • 第十六届蓝桥杯B组第二题
  • 什么是分布式光伏系统?屋顶分布式光伏如何并网?
  • 高质量老年生活:从主动健康管理到预防医学的社会价值
  • 在 Spring Boot 中选择合适的 HTTP 客户端
  • 2025年社交APP安全防御指南:抵御DDoS与CC攻击的实战策略
  • NLP基础