【高级React技术】当企业级项目采用Refs 转发和使用 HOC 解决横切关注点问题
Refs 转发
引用转发是一种通过组件将引用自动传递到其子组件之一的技术。大多数应用程序中的组件通常不需要这样做。但它对某些组件非常有用,尤其是可重用的组件库。
function FancyButton(props) {return (<button className="FancyButton">{props.children}</button>);
}
React组件隐藏其实现细节,包括其渲染结果。使用FancyButton的其他组件通常不需要获取内部DOM元素按钮的ref。这很好,因为它可以防止组件过度依赖其他组件的DOM结构。
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>;
虽然这种封装对于应用程序级组件(如FeedStory或Comment)非常理想,但对于高度可重用的“叶”组件(如FancyButton或MyTextInput)来说可能不太方便。这些组件倾向于以类似于传统DOM按钮和输入的方式在整个应用程序中使用,访问它们的DOM节点对于管理焦点、选择或动画是不可避免的。
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;
}
我们调用React CreateRef创建一个React ref并将其分配给ref变量。 通过将ref指定为JSX属性,我们将其传递给<FancyButton ref={ref}>。 React将ref传递给forwardRef中的函数(props,ref)=>…作为其第二个参数。 我们将ref参数向下转发到<button ref={ref}>,并将其指定为JSX属性。 安装ref时,ref当前将指向<button>DOM节点。
class FancyButton extends React.Component {focus() {// ...}// ...
}// 我们导出 LogProps,而不是 FancyButton。
// 虽然它也会渲染一个 FancyButton。
export default logProps(FancyButton);
幸运的是,我们可以使用React。forwardRef API显式地将引用转发到内部FancyButton组件。反应ForwardRef接受接收props和ref参数的渲染函数,并返回React节点。
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);
}
需要返回多个 元素以使渲染的 HTML 有效。如果在的 render() 中使用了父 div,则生成的 HTML 将无效。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
高阶组件(HOC)是React中重用组件逻辑的高级技术。HOC本身不是React API的一部分。这是一种基于React综合特性的设计模式。
class CommentList extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.state = {// 假设 "DataSource" 是个全局范围内的数据源变量comments: DataSource.getComments()};}componentDidMount() {// 订阅更改DataSource.addChangeListener(this.handleChange);}componentWillUnmount() {// 清除订阅DataSource.removeChangeListener(this.handleChange);}handleChange() {// 当数据源更新时,更新组件状态this.setState({comments: DataSource.getComments()});}render() {return (<div>{this.state.comments.map((comment) => (<Comment comment={comment} key={comment.id} />))}</div>);}
}
CommentList和BlogPost是不同的-它们在DataSource上调用不同的方法并呈现不同的结果。但它们的大多数实现都是相同的: 装载时,向DataSource添加更改侦听器。 在侦听器内部,当数据源发生更改时,会调用setState。 卸载时,删除侦听器。 可以想象,在大型应用程序中,这种订阅DataSource并调用setState的模式会反复出现。我们需要一个抽象,它允许我们在一个地方定义这个逻辑,并在多个组件之间共享它。这就是高阶组件的优势所在。 对于订阅了DataSource的组件,例如CommentList和BlogPost,我们可以编写一个创建组件函数。此函数将接受子组件作为其参数之一,子组件将使用订阅数据作为属性。让我们使用Subscription调用函数:
const CommentListWithSubscription = withSubscription(CommentList,(DataSource) => DataSource.getComments()
);const BlogPostWithSubscription = withSubscription(BlogPost,(DataSource, props) => DataSource.getBlogPost(props.id)
);
使用 HOC 解决横切关注点问题
由于withSubscription是一个通用函数,因此您可以根据需要添加或删除参数。例如,您可能希望使数据属性的名称可配置,以进一步将HOC与包装器组件隔离开来。或者您可以接受用于配置shouldComponentUpdate的参数,或用于配置数据源的参数。因为HOC可以控制组件的定义方式,所以这一切都成为可能。 与组件一样,withSubscription和包装器组件之间的契约完全基于它们之间传递的属性。这种依赖模式可以很容易地替换HOC,只要它们为封装组件提供相同的支持。例如,当您需要使用其他数据库获取数据时,这很有用。
function logProps(InputComponent) {InputComponent.prototype.componentDidUpdate = function(prevProps) {console.log('Current props: ', this.props);console.log('Previous props: ', prevProps);};return InputComponent;
}const EnhancedComponent = logProps(InputComponent);
每次调用 logProps 时,增强组件都会有 log 输出。返回原始的 input 组件,暗示它已经被修改。
const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))// ... 你可以编写组合工具函数
// compose(f, g, h) 等同于 (...args) => f(g(h(...args)))
const enhance = compose(// 这些都是单参数的 HOCwithRouter,connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)
这种形式可能看起来很混乱或不必要,但它有一个有用的属性。与connect函数返回的单个参数HOC一样,它具有签名Component=>Component。具有相同输出类型和输入类型的函数可以很容易地组合。
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享
【高级React技术】当企业级项目采用Refs 转发和使用 HOC 解决横切关注点问题相关推荐
- web前端高级React - React从入门到进阶之高阶组件
第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...
- web前端高级React - React从入门到进阶之Render Props
第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南...
一.AgileEAS.NET平台简介 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本.缩短开发时间,快速适应市场 ...
- 25 Refs转发机制与在高阶组件中的使用
将子节点的ref暴露给父节点 16.3以上 Refs转发,将ref自动通过组件传递给子组件 1. 在父组件创建ref对象 2. 给子组件赋值ref 3. 通过React.forward向子组件转发re ...
- 深入react技术栈(6):React和DOM
我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 React DoM findDoMNode render React得不稳定方法 Refs React之外得DoM操作 文章参考深入R ...
- 实战react技术栈+express前后端博客项目(3)-- 后端路由、代理以及静态资源托管等配置说明...
项目地址:github.com/Nealyang/Re- 本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人.遂想,何不一边记录踩坑,一边分享收获呢.分享当然是好的, ...
- web前端高级React - React从入门到进阶之组件的懒加载及上下文Context
第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...
- Flink - 尚硅谷- 大数据高级 Flink 技术精讲 - 2
七.Flink 时间语义与 Watermark 7.1 Flink 中的时间语义 7.2 设置 Event Time 7.3 水位线 - Watermark 7.3.1 基本概念 7.3.2 Wate ...
- 3D场景高级合成技术学习
MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch |语言:英语+中英文字幕(根据原英文字幕机译更准确)|时长:3h 47m |大小解压后:3.61 GB 含课程文 ...
最新文章
- 15 张图,了解一下 TCP/IP 必知也必会的 10个要点
- 深度学习分布式训练小结
- Android 全局悬浮按钮,悬浮按钮点击事件
- JVM005_synchronized、同步指令、管程、MESA
- java面经_字节跳动 暑期实习 广告部 后台开发 java 一二面经
- python 图像模糊处理实现
- 为什么“隐性知识”比“刻意练习”更重要?
- 网站建设费用贵和便宜有什么区别?
- [小工具] 微信小程序代码压缩器
- 关于小区物业自治方案的探讨
- html 播放本地视频(获取磁盘文件url)
- Catalan数的分析和应用
- IT培训有靠谱的机构吗,长什么样的?
- 重来之大学版|学习篇-为什么要学习?为什么要终身学习?别一上来就“费曼学习法”,先学习学习再学习
- android接入第三方SDK
- tx2 安装opencv4.1.1及opencv_contrib-4.1.1
- 微信5秒超时 php异步,微信公众号-5秒内不回复测试并处理方案,顺便复习php 时间执行...
- 视频直播终端开发之微信小程序版
- iOS App 上架App Store及提交审核(Appuploader)
- python虚假评论识别程序_还在刷虚假评论?小心了,可以检测虚假评论的第三方工具来了...