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 解决横切关注点问题相关推荐

  1. web前端高级React - React从入门到进阶之高阶组件

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  2. web前端高级React - React从入门到进阶之Render Props

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  3. 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南...

    一.AgileEAS.NET平台简介 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本.缩短开发时间,快速适应市场 ...

  4. 25 Refs转发机制与在高阶组件中的使用

    将子节点的ref暴露给父节点 16.3以上 Refs转发,将ref自动通过组件传递给子组件 1. 在父组件创建ref对象 2. 给子组件赋值ref 3. 通过React.forward向子组件转发re ...

  5. 深入react技术栈(6):React和DOM

    我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 React DoM findDoMNode render React得不稳定方法 Refs React之外得DoM操作 文章参考深入R ...

  6. 实战react技术栈+express前后端博客项目(3)-- 后端路由、代理以及静态资源托管等配置说明...

    项目地址:github.com/Nealyang/Re- 本想等项目做完再连载一波系列博客,随着开发的进行,也是的确遇到了不少坑,请教了不少人.遂想,何不一边记录踩坑,一边分享收获呢.分享当然是好的, ...

  7. web前端高级React - React从入门到进阶之组件的懒加载及上下文Context

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  8. Flink - 尚硅谷- 大数据高级 Flink 技术精讲 - 2

    七.Flink 时间语义与 Watermark 7.1 Flink 中的时间语义 7.2 设置 Event Time 7.3 水位线 - Watermark 7.3.1 基本概念 7.3.2 Wate ...

  9. 3D场景高级合成技术学习

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch |语言:英语+中英文字幕(根据原英文字幕机译更准确)|时长:3h 47m |大小解压后:3.61 GB 含课程文 ...

最新文章

  1. 15 张图,了解一下 TCP/IP 必知也必会的 10个要点
  2. 深度学习分布式训练小结
  3. Android 全局悬浮按钮,悬浮按钮点击事件
  4. JVM005_synchronized、同步指令、管程、MESA
  5. java面经_字节跳动 暑期实习 广告部 后台开发 java 一二面经
  6. python 图像模糊处理实现
  7. 为什么“隐性知识”比“刻意练习”更重要?
  8. 网站建设费用贵和便宜有什么区别?
  9. [小工具] 微信小程序代码压缩器
  10. 关于小区物业自治方案的探讨
  11. html 播放本地视频(获取磁盘文件url)
  12. Catalan数的分析和应用
  13. IT培训有靠谱的机构吗,长什么样的?
  14. 重来之大学版|学习篇-为什么要学习?为什么要终身学习?别一上来就“费曼学习法”,先学习学习再学习
  15. android接入第三方SDK
  16. tx2 安装opencv4.1.1及opencv_contrib-4.1.1
  17. 微信5秒超时 php异步,微信公众号-5秒内不回复测试并处理方案,顺便复习php 时间执行...
  18. 视频直播终端开发之微信小程序版
  19. iOS App 上架App Store及提交审核(Appuploader)
  20. python虚假评论识别程序_还在刷虚假评论?小心了,可以检测虚假评论的第三方工具来了...

热门文章

  1. 软注意力和硬注意力的对比
  2. 转移到csdn,先来个霍金的《时间简史》小随笔吧。。。
  3. java编程软件手机版_Java编程软件(Alice 3)
  4. 网络抓包原理及Fiddler的使用
  5. Caffe训练数据转换为HD5与LMDB的代码实现
  6. 小红书被罚30万,理由:违反未成年人保护法
  7. oracle 递归查询,Oracle 递归查询
  8. 【工具】workflowy - 笔记清单工具
  9. java后台运行命令,停止java后端运行
  10. VUE的proxyTable使用记录和java跨域设置