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 EasyUI中对表格进行编辑的实现代码
Jun 10 Javascript
详解JavaScript设计模式开发中的桥接模式使用
May 18 Javascript
深入理解angularjs过滤器
May 25 Javascript
js弹出窗口返回值的简单实例
May 28 Javascript
jQuery实现圣诞节礼物传送(花式轮播)
Dec 25 Javascript
老生常谈js数据类型
Aug 03 Javascript
BootStrap模态框和select2合用时input无法获取焦点的解决方法
Sep 01 Javascript
JavaScript基于面向对象实现的猜拳游戏
Jan 03 Javascript
vue中的watch监听数据变化及watch中各属性的详解
Sep 11 Javascript
vue动态添加路由addRoutes之不能将动态路由存入缓存的解决
Feb 19 Javascript
jQuery实现的解析本地 XML 文档操作示例
Apr 30 jQuery
vant 时间选择器--开始时间和结束时间实例
Nov 04 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
比较discuz和ecshop的截取字符串函数php版
2012/09/03 PHP
ajax返回值中有回车换行、空格的解决方法分享
2013/10/24 PHP
Zend Guard使用指南及问题处理
2015/01/07 PHP
PHP异常处理Exception类
2015/12/11 PHP
PHP结合Ffmpeg快速搭建流媒体服务的实践记录
2018/10/31 PHP
php使用event扩展的io复用测试的示例
2020/10/20 PHP
另类调用flash无须激活的方法
2006/12/27 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
学习使用grunt来打包JavaScript和CSS程序的教程
2016/01/04 Javascript
神奇!js+CSS+DIV实现文字颜色渐变效果
2016/03/16 Javascript
JavaScript中的继承之类继承
2016/05/01 Javascript
JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解
2016/05/31 Javascript
浅谈JavaScript前端开发的MVC结构与MVVM结构
2016/06/03 Javascript
最丑的时钟效果!js canvas时钟制作方法
2016/08/15 Javascript
js实现开启密码大写提示
2016/12/21 Javascript
JQuery 获取多个select标签option的text内容(实例)
2017/09/07 jQuery
vue如何引入sass全局变量
2018/06/28 Javascript
浅谈VUE单页应用首屏加载速度优化方案
2018/08/28 Javascript
JS中appendChild追加子节点无效的解决方法
2018/10/14 Javascript
layDate插件设置开始和结束时间
2018/11/15 Javascript
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
微信公众平台 发送模板消息(Java接口开发)
2019/04/17 Javascript
js实现ajax的用户简单登入功能
2020/06/18 Javascript
echarts实现晶体球面投影的实例教程
2020/10/10 Javascript
vue实现移动端返回顶部
2020/10/12 Javascript
Vue-Ant Design Vue-普通及自定义校验实例
2020/10/24 Javascript
python对象与json相互转换的方法
2019/05/07 Python
python读取hdfs并返回dataframe教程
2020/06/05 Python
Python confluent kafka客户端配置kerberos认证流程详解
2020/10/12 Python
python将下载到本地m3u8视频合成MP4的代码详解
2020/11/24 Python
英国户外装备和冒险服装零售商:alloutdoor
2018/01/30 全球购物
澳大利亚在线消费电子产品商店:TobyDeals
2020/01/05 全球购物
Agoda中文官网:安可达(低价预订全球酒店)
2021/01/18 全球购物
婚庆公司的创业计划书
2014/01/22 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS