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 相关文章推荐
jqeury eval将字符串转换json的方法
Jan 20 Javascript
使用javascript获取flash加载的百分比的实现代码
May 25 Javascript
JS预览图像将本地图片显示到浏览器上
Aug 25 Javascript
JS数组的遍历方式for循环与for...in
Jul 31 Javascript
JavaScript实现同一页面内两个表单互相传值的方法
Aug 12 Javascript
js实现表单Radio切换效果的方法
Aug 17 Javascript
js中获取时间new Date()的全面介绍
Jun 20 Javascript
利用BootStrap弹出二级对话框的简单实现方法
Sep 21 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
Jan 31 Javascript
vue组件之间通信方式实例总结【8种方式】
Feb 22 Javascript
vue鼠标悬停事件实例详解
Apr 01 Javascript
vue 防止页面加载时看到花括号的解决操作
Nov 09 Javascript
详解前端路由实现与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
提升PHP执行速度全攻略(上)
2006/10/09 PHP
php递归实现无限分类生成下拉列表的函数
2010/08/08 PHP
学习php设计模式 php实现命令模式(command)
2015/12/08 PHP
判断JavaScript对象是否可用的最正确方法分析
2008/10/03 Javascript
jQuery.extend 函数的详细用法
2012/06/27 Javascript
javascript实现禁止复制网页内容
2014/12/16 Javascript
jQuery超酷平面式时钟效果代码分享
2020/03/30 Javascript
JS正则RegExp.test()使用注意事项(不具有重复性)
2016/12/28 Javascript
详解Angular 4.x Injector
2017/05/04 Javascript
React Native基础入门之初步使用Flexbox布局
2018/07/02 Javascript
微信小程序实现的自定义分享功能示例
2019/02/12 Javascript
elementUI select组件value值注意事项详解
2019/05/29 Javascript
vue css 引入asstes中的图片无法显示的四种解决方法
2020/03/16 Javascript
JavaScript Dom实现轮播图原理和实例
2021/02/19 Javascript
[58:23]LGD vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
python MySQLdb Windows下安装教程及问题解决方法
2015/05/09 Python
利用numpy和pandas处理csv文件中的时间方法
2018/04/19 Python
Python将list中的string批量转化成int/float的方法
2018/06/26 Python
简单易懂Pytorch实战实例VGG深度网络
2019/08/27 Python
Python3如何判断三角形的类型
2020/04/12 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
HTML中使用SVG与SVG预定义形状元素介绍
2013/06/28 HTML / CSS
美国受欢迎的女性牛仔裤品牌:DL1961
2016/11/12 全球购物
澳大利亚家具和家居用品在线商店:Interiors Online
2018/03/05 全球购物
手工制作的意大利礼服鞋:Ace Marks
2018/12/15 全球购物
HomeAway英国:全球领先的度假租赁在线市场
2020/02/03 全球购物
授权委托书格式模板
2014/04/03 职场文书
幼儿园教师演讲稿
2014/05/06 职场文书
标准毕业生自荐信
2014/06/24 职场文书
爱护公物演讲稿
2014/09/09 职场文书
和谐家庭事迹材料
2014/12/20 职场文书
单身申明具结书
2015/02/26 职场文书
公司市场部岗位职责
2015/04/15 职场文书
亮剑观后感300字
2015/06/05 职场文书
2016年中学端午节主题活动总结
2016/04/01 职场文书
pytorch--之halfTensor的使用详解
2021/05/24 Python