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 相关文章推荐
jQuery 剧场版 你必须知道的javascript
May 27 Javascript
javascript 主动派发事件总结
Aug 09 Javascript
JQuery操作单选按钮以及复选按钮示例
Sep 23 Javascript
解决Extjs4中form表单提交后无法进入success函数问题
Nov 26 Javascript
jQuery实现当前页面标签高亮显示的方法
Mar 10 Javascript
jQuery实现图片轮播效果代码(基于jquery.pack.js插件)
Jun 02 Javascript
浅谈JavaScript中面向对象的的深拷贝和浅拷贝
Aug 01 Javascript
vue左右侧联动滚动的实现代码
Jun 06 Javascript
详解angular2 控制视图的封装模式
Dec 27 Javascript
js中arguments对象的深入理解
May 14 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
Sep 28 Javascript
ES2020 已定稿,真实场景案例分析
May 25 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
如何开始收听短波广播
2021/03/01 无线电
随机头像PHP版
2006/10/09 PHP
浅析PHP水印技术
2007/02/14 PHP
DEDECMS首页调用图片集里的多张图片
2015/06/05 PHP
Avengerls vs KG BO3 第二场2.18
2021/03/10 DOTA
javascript不同页面传值的改进版
2008/09/30 Javascript
jquery Moblie入门—hello world的示例代码学习
2013/01/08 Javascript
js加减乘除丢失精度问题解决方法
2014/05/16 Javascript
浅谈EasyUI中Treegrid节点的删除
2015/03/01 Javascript
Javascript blur与click冲突解决办法
2017/01/09 Javascript
基于jQuery制作小图标上下滑动特效
2017/01/18 Javascript
微信小程序 九宫格实例代码
2017/01/21 Javascript
webpack配置sass模块的加载的方法
2017/07/30 Javascript
使用jquery的jsonp如何发起跨域请求及其原理详解
2017/08/17 jQuery
使用 Vue 实现一个虚拟列表的方法
2019/08/20 Javascript
vue+vuex+axios从后台获取数据存入vuex,组件之间共享数据操作
2020/07/31 Javascript
python中异常捕获方法详解
2017/03/03 Python
Python字符串格式化的方法(两种)
2017/09/19 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
2018/04/18 Python
Python UnboundLocalError和NameError错误根源案例解析
2018/10/31 Python
Python安装Flask环境及简单应用示例
2019/05/03 Python
Python3的unicode编码转换成中文的问题及解决方案
2019/12/10 Python
Python selenium爬取微博数据代码实例
2020/05/22 Python
python speech模块的使用方法
2020/09/09 Python
Python实现迪杰斯特拉算法并生成最短路径的示例代码
2020/12/01 Python
css3闪亮进度条效果实现思路及代码
2013/04/17 HTML / CSS
手把手教你实现一个canvas智绘画板的方法
2019/03/04 HTML / CSS
KIKO美国官网:意大利的平价彩妆品牌
2017/05/16 全球购物
成人毕业生自我鉴定
2013/10/18 职场文书
大学生简历求职信
2014/06/24 职场文书
2014年终个人工作总结
2014/11/07 职场文书
面试通知短信
2015/04/20 职场文书
推广普通话的宣传语
2015/07/13 职场文书
公司保密管理制度
2015/08/04 职场文书
企业法人任命书
2015/09/21 职场文书
心理学培训心得体会
2016/01/22 职场文书