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 相关文章推荐
了解一点js的Eval函数
Jul 26 Javascript
基于JavaScript实现继承机制之调用call()与apply()的方法详解
May 07 Javascript
使用js修改客户端注册表的方法
Aug 09 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 Javascript
微信小程序 五星评价功能的实现
Mar 09 Javascript
Bootstrap缩略图的创建方法
Mar 22 Javascript
JavaScript实现图片懒加载的方法分析
Jul 05 Javascript
node.js学习笔记之koa框架和简单爬虫练习
Dec 13 Javascript
JS实现二维数组元素的排列组合运算简单示例
Jan 28 Javascript
vue项目前端错误收集之sentry教程详解
May 27 Javascript
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
Sep 01 Javascript
JS表格的动态操作完整示例
Jan 13 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随机输出名人名言的代码
2012/10/07 PHP
php版小黄鸡simsimi聊天机器人接口分享
2014/01/26 PHP
PHP实现发送微博消息功能完整示例
2019/12/04 PHP
PHP7原生MySQL数据库操作实现代码
2020/07/03 PHP
jquery 插件实现图片延迟加载效果代码
2010/02/06 Javascript
扩展IE中一些不兼容的方法如contains、startWith等等
2014/01/09 Javascript
Jquery 实现table样式的设定
2015/01/28 Javascript
JS设置网页图片vspace和hspace属性的方法
2015/04/01 Javascript
JavaScript简单表格编辑功能实现方法
2015/04/16 Javascript
Javascript学习之谈谈JS的全局变量跟局部变量(推荐)
2016/08/28 Javascript
JavaScript递归操作实例浅析
2016/10/31 Javascript
Canvas 制作动态进度加载水球详解及实例代码
2016/12/09 Javascript
angularjs点击图片放大实现上传图片预览
2017/02/24 Javascript
Node.js 中exports 和 module.exports 的区别
2017/03/14 Javascript
vue2.0 实现导航守卫(路由守卫)
2018/05/21 Javascript
Puppeteer 爬取动态生成的网页实战
2018/11/14 Javascript
优化Vue项目编译文件大小的方法步骤
2019/05/27 Javascript
微信小程序 腾讯地图SDK 获取当前地址实现解析
2019/08/12 Javascript
vue调用语音播放的方法
2019/09/27 Javascript
跟老齐学Python之从if开始语句的征程
2014/09/14 Python
Python字符串和文件操作常用函数分析
2015/04/08 Python
定制FileField中的上传文件名称实例
2017/08/23 Python
django中静态文件配置static的方法
2018/05/20 Python
python 美化输出信息的实例
2018/10/15 Python
解决pyinstaller打包发布后的exe文件打开控制台闪退的问题
2019/06/21 Python
python3处理word文档实例分析
2020/12/01 Python
CSS3 真的会替代 SCSS 吗
2021/03/09 HTML / CSS
aden + anais官方网站:婴儿襁褓、毯子、尿布和服装
2017/06/21 全球购物
某/etc/fstab文件中的某行如下: /dev/had5 /mnt/dosdata msdos defaults,usrquota 1 2 请解释其含义
2013/09/18 面试题
AJAX都有哪些有点和缺点
2012/11/03 面试题
销售竞赛活动方案
2014/08/23 职场文书
践行党的群众路线心得体会
2014/11/05 职场文书
2015年九一八事变纪念日演讲稿
2015/03/19 职场文书
2015年暑期社会实践方案
2015/07/14 职场文书
2015年物流客服工作总结
2015/07/27 职场文书
婚宴新郎致辞
2015/07/28 职场文书