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 相关文章推荐
新浪的图片新闻效果
Jan 13 Javascript
在你的网页中嵌入外部网页的方法
Apr 02 Javascript
用jquery设置按钮的disabled属性的实现代码
Nov 28 Javascript
jQuery之$(document).ready()使用介绍
Apr 05 Javascript
jquery显示和隐藏div特效实例
Feb 27 Javascript
jQuery scrollFix滚动定位插件
Apr 01 Javascript
js游戏人物上下左右跑步效果代码分享
Aug 28 Javascript
JS实现经典的中国地区三级联动下拉菜单功能实例【测试可用】
Jun 06 Javascript
vue2.0开发入门笔记之.vue文件的生成和使用
Sep 19 Javascript
layui表格 列自动适应大小失效的解决方法
Sep 06 Javascript
JS如何实现封装列表右滑动删除收藏按钮
Jul 23 Javascript
vue+elementUI动态增加表单项并添加验证的代码详解
Dec 17 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
php面向对象全攻略 (五) 封装性
2009/09/30 PHP
深入apache配置文件httpd.conf的部分参数说明
2013/06/28 PHP
php ajax异步读取rss文档数据
2016/03/29 PHP
php通过smtp邮件验证登陆的方法
2016/05/11 PHP
PHP类相关知识点实例总结
2016/09/28 PHP
laravel5.5添加echarts实现画图功能的方法
2019/10/09 PHP
Firefox和IE浏览器兼容JS脚本写法小结
2008/07/07 Javascript
javascript encodeURI和encodeURIComponent的比较
2010/04/03 Javascript
24款热门实用的jQuery插件推荐
2014/12/24 Javascript
jquery实现简单的表单验证
2015/11/17 Javascript
AngularJS中watch监听用法分析
2016/11/04 Javascript
JavaScript实现垂直滚动条效果
2017/01/18 Javascript
Bootstrap下拉菜单样式
2017/02/07 Javascript
javascript 操作cookies详解及实例
2017/02/22 Javascript
详解vue axios中文文档
2017/09/12 Javascript
移动端效果之Swiper详解
2017/10/09 Javascript
原生JS实现的双色球功能示例
2018/02/02 Javascript
vue-cli3.0 特性解读
2018/04/22 Javascript
vue.js实现的绑定class操作示例
2018/07/06 Javascript
JavaScript解析及序列化JSON的方法实例分析
2019/01/04 Javascript
在layui中对table中的数据进行判断(0、1)转换为提示信息的方法
2019/09/28 Javascript
nuxt.js服务端渲染中axios和proxy代理的配置操作
2020/11/06 Javascript
微信小程序实现左滑删除效果
2020/11/18 Javascript
python读写ini文件示例(python读写文件)
2014/03/25 Python
python函数形参用法实例分析
2015/08/04 Python
如何用itertools解决无序排列组合的问题
2017/05/18 Python
Python3标准库总结
2019/02/19 Python
Django 实现将图片转为Base64,然后使用json传输
2020/03/27 Python
英国123鲜花网站:123 Flowers
2019/07/07 全球购物
财务部岗位职责
2013/11/19 职场文书
教师自我反思材料
2014/02/14 职场文书
社区义诊活动总结
2014/04/30 职场文书
个人批评与自我批评
2014/10/15 职场文书
乒乓球比赛通知
2015/04/27 职场文书
求职自我评价参考范文
2019/05/16 职场文书
用基于python的appium爬取b站直播消费记录
2021/04/17 Python