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 相关文章推荐
DOM 中的事件处理介绍
Jan 18 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
May 17 Javascript
JavaScript中for循环的使用详解
Jun 03 Javascript
easyui-combobox 实现简单的自动补全功能示例
Nov 08 Javascript
Vue.js+Layer表格数据绑定与实现更新的实例
Mar 07 Javascript
React key值的作用和使用详解
Aug 23 Javascript
vue+node实现图片上传及预览的示例方法
Nov 22 Javascript
详解Vue基于vue-quill-editor富文本编辑器使用心得
Jan 03 Javascript
如何在微信小程序中实现Mixins方案
Jun 20 Javascript
json解析大全 双引号、键值对不在一起的情况
Dec 06 Javascript
原生JavaScript实现进度条
Feb 19 Javascript
80行代码写一个Webpack插件并发布到npm
May 24 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
用DBSQL类加快开发MySQL数据库程序的速度
2006/10/09 PHP
php chr() ord()中文截取乱码问题解决方法
2008/09/08 PHP
老版本PHP转义Json里的特殊字符的函数
2015/06/08 PHP
php面向对象与面向过程两种方法给图片添加文字水印
2015/08/26 PHP
十个PHP高级应用技巧果断收藏
2015/09/25 PHP
PHP实现图片上传并压缩
2015/12/22 PHP
Laravel框架基础语法与知识点整理【模板变量、输出、include引入子视图等】
2019/12/03 PHP
利用javascript/jquery对上传文件格式过滤的方法
2009/07/25 Javascript
Javascript 匿名函数及其代码模式原理
2010/03/19 Javascript
js操作textarea方法集合封装(兼容IE,firefox)
2011/02/22 Javascript
基于jquery自己写tab滑动门(通用版)
2012/10/30 Javascript
jQuery实现3D文字特效的方法
2015/03/10 Javascript
jquery中checkbox使用方法简单实例演示
2015/11/24 Javascript
js学习阶段总结(必看篇)
2016/06/16 Javascript
onmouseover事件和onmouseout事件全面理解
2016/08/15 Javascript
基于Bootstrap模态对话框只加载一次 remote 数据的解决方法
2017/07/09 Javascript
手机注册发送验证码倒计时的简单实例
2017/11/15 Javascript
使用JavaScript破解web
2018/09/28 Javascript
PyQt5主窗口动态加载Widget实例代码
2018/02/07 Python
使用python进行文本预处理和提取特征的实例
2018/06/05 Python
python爬虫的数据库连接问题【推荐】
2018/06/25 Python
python模拟登陆,用session维持回话的实例
2018/12/27 Python
利用python实现AR教程
2019/11/20 Python
Python 项目转化为so文件实例
2019/12/23 Python
python调用摄像头的示例代码
2020/09/28 Python
初探CSS3中的calc()功能
2015/07/14 HTML / CSS
升职自荐信范文
2013/10/05 职场文书
初中体育教学反思
2014/01/14 职场文书
总经理助理职责
2014/02/04 职场文书
青岛海底世界导游词
2015/02/11 职场文书
赢在中国观后感
2015/06/02 职场文书
2015年环卫处个人工作总结
2015/07/27 职场文书
医院岗前培训心得体会
2016/01/08 职场文书
MySQL和Oracle批量插入SQL的通用写法示例
2021/11/17 MySQL
10大幻兽系恶魔果实 蝙蝠果实上榜,第一自愈能力强
2022/03/18 日漫
springboot layui hutool Excel导入的实现
2022/03/31 Java/Android