React进阶学习之组件的解耦之道


Posted in Javascript onAugust 07, 2017

前言

众所周知,React中的组件非常的灵活可扩展,不过随着业务复杂度的增加和许多外部工具库的引入,组件往往也会显得浮肿,接下来我们就一起来看看常见的几种,遵循单一职责原则的,组件分割与解耦的方法,话不多说了,来一起看看详细的介绍:

一、分割 render 函数

当一个组件渲染的内容较多时,有一个快速并且通用的方法是创建sub-render函数来简化原来庞大的 render

class Panel extends React.Component {
 renderHeading() {
 // ...
 }

 renderBody() {
 // ...
 }

 render() {
 return (
 <div>
 {this.renderHeading()}
 {this.renderBody()}
 </div>
 );
 }
}

为了再次简化sub-render函数,我们还可以采用Functional Components写法,这种方式生成了更小的处理单元,且更有利于测试

const PanelHeader = (props) => (
 // ...
);

const PanelBody = (props) => (
 // ...
);

class Panel extends React.Component {
 render() {
 return (
 <div>
 // Nice and explicit about which props are used
 <PanelHeader title={this.props.title}/>
 <PanelBody content={this.props.content}/>
 </div>
 );
 }
}

二、用 props 传递元素

如果一个组件的状态或配置较多,我们可以运用props传递元素而不仅是数据,比如再声明一个组件,使其中的父组件只专注于配置

class CommentTemplate extends React.Component {
 static propTypes = {
 // Declare slots as type node
 metadata: PropTypes.node,
 actions: PropTypes.node,
 };

 render() {
 return (
 <div>
 <CommentHeading>
  <Avatar user={...}/>

  // Slot for metadata
  <span>{this.props.metadata}</span>

 </CommentHeading>
 <CommentBody/>
 <CommentFooter>
  <Timestamp time={...}/>

  // Slot for actions
  <span>{this.props.actions}</span>

 </CommentFooter>
 </div>
 );
 }
}

父组件

class Comment extends React.Component {
 render() {
 const metadata = this.props.publishTime ?
 <PublishTime time={this.props.publishTime} /> :
 <span>Saving...</span>;

 const actions = [];
 if (this.props.isSignedIn) {
 actions.push(<LikeAction />);
 actions.push(<ReplyAction />);
 }
 if (this.props.isAuthor) {
 actions.push(<DeleteAction />);
 }

 return <CommentTemplate metadata={metadata} actions={actions} />;
 }
}

三、使用高阶组件

实现点击某组件的超链接,发送该组件的 ID,我们大多的解决方法可能如下

class Document extends React.Component {
 componentDidMount() {
 ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
 }

 componentWillUnmount() {
 ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
 }

 onClick = (e) => {
 if (e.target.tagName === 'A') { // Naive check for <a> elements
 sendAnalytics('link clicked', {
 documentId: this.props.documentId // Specific information to be sent
 });
 }
 };

 render() {
 // ...
 }
}

然而它却存在代码不能复用,组件重构困难等问题

我们可以使用高阶组件来解决这些问题,顾名思义,高阶组件就是一个函数,传给它一个组件,它返回一个新的组件

function withLinkAnalytics(mapPropsToData, WrappedComponent) {
 class LinkAnalyticsWrapper extends React.Component {
 componentDidMount() {
 ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
 }

 componentWillUnmount() {
 ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
 }

 onClick = (e) => {
 if (e.target.tagName === 'A') { // Naive check for <a> elements
 const data = mapPropsToData ? mapPropsToData(this.props) : {};
 sendAnalytics('link clicked', data);
 }
 };

 render() {
 // Simply render the WrappedComponent with all props
 return <WrappedComponent {...this.props} />;
 }
 }

 return LinkAnalyticsWrapper;
}

简化代码如下

class Document extends React.Component {
 render() {
 // ...
 }
}

export default withLinkAnalytics((props) => ({
 documentId: props.documentId
}), Document);

总结

以上 3 个 React 组件的解耦重构方法都可以直接拿来运用,最开始可能会觉得有点棘手,但是没关系,只要坚持下来,你就会写出更强壮和可复用的代码。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

原文链接: Techniques for decomposing React components

Javascript 相关文章推荐
用javascript实现的支持lrc歌词的播放器
May 17 Javascript
Sample script that displays all of the users in a given SQL Server DB
Jun 16 Javascript
层序遍历在ExtJs的TreePanel中的应用
Oct 16 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
Oct 15 Javascript
判断复选框是否被选中的两种方法
Jun 04 Javascript
JS实现在线统计一个页面内鼠标点击次数的方法
Feb 28 Javascript
AngularJS双向绑定和依赖反转实例详解
Apr 15 Javascript
Angular2关于@angular/cli默认端口号配置的问题
Jul 15 Javascript
React如何解决fetch跨域请求时session失效问题
Nov 02 Javascript
Vue开发中遇到的跨域问题及解决方法
Feb 11 Javascript
JavaScript实现图片伪异步上传过程解析
Apr 10 Javascript
vue.js 使用原生js实现轮播图
Apr 26 Vue.js
详解前端路由实现与react-router使用姿势
Aug 07 #Javascript
React中使用collections时key的重要性详解
Aug 07 #Javascript
react路由配置方式详解
Aug 07 #Javascript
深入理解vue.js中$watch的oldvalue与newValue
Aug 07 #Javascript
JavaScript调试之console.log调试的一个小技巧分享
Aug 07 #Javascript
react native仿微信PopupWindow效果的实例代码
Aug 07 #Javascript
jquery+css实现简单的图片轮播效果
Aug 07 #jQuery
You might like
使用MaxMind 根据IP地址对访问者定位
2006/10/09 PHP
用PHP将数据导入到Foxmail
2006/10/09 PHP
傻瓜化配置PHP环境――Appserv
2006/12/13 PHP
2020最新版 PhpStudy V8.1版本下载安装使用详解
2020/10/30 PHP
点击广告后才能获得下载地址
2006/10/26 Javascript
用js解决数字不能换行问题
2010/08/10 Javascript
新发现一个骗链接的方法(js读取cookies)
2012/01/11 Javascript
JavaScript计时器示例分析
2015/02/05 Javascript
JavaScript生成随机数的4种自定义函数分享
2015/02/28 Javascript
jquery实现点击查看更多内容控制段落文字展开折叠效果
2015/08/06 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
JavaScript递归操作实例浅析
2016/10/31 Javascript
通过Ajax使用FormData对象无刷新上传文件方法
2016/12/08 Javascript
Node.js学习之地址解析模块URL的使用详解
2017/09/28 Javascript
JavaScript实现为事件句柄绑定监听函数的方法分析
2017/11/14 Javascript
判断文字超过2行添加展开按钮,未超过则不显示,溢出部分显示省略号
2019/04/28 Javascript
原生javascript中this几种常见用法总结
2020/02/24 Javascript
jquery实现的放大镜效果示例
2020/02/24 jQuery
Python 实现12306登录功能实例代码
2018/02/09 Python
Windows环境下python环境安装使用图文教程
2018/03/13 Python
python 实现对数据集的归一化的方法(0-1之间)
2018/07/17 Python
Python将一个Excel拆分为多个Excel
2018/11/07 Python
Windows系统Python直接调用C++ DLL的方法
2019/08/01 Python
Python 词典(Dict) 加载与保存示例
2019/12/06 Python
布隆过滤器的概述及Python实现方法
2019/12/08 Python
scrapy与selenium结合爬取数据(爬取动态网站)的示例代码
2020/09/28 Python
css3一个简易的 LED 数字时钟实现方法
2020/01/15 HTML / CSS
浅析HTML5中header标签的用法
2016/06/24 HTML / CSS
材料化学应届生求职信
2013/10/09 职场文书
物流司机岗位职责
2013/12/28 职场文书
微博营销计划书
2014/01/10 职场文书
医科大学毕业生自荐信
2014/02/03 职场文书
办公室岗位职责
2015/02/04 职场文书
2015年七一建党节慰问信
2015/03/23 职场文书
2016年三八红旗手先进事迹材料
2016/02/26 职场文书
什么是动态刷新率DRR? Windows11动态刷新率功能介绍
2021/11/21 数码科技