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 相关文章推荐
40个新鲜出炉的jQuery 插件和免费教程[上]
Jul 24 Javascript
Js-$.extend扩展方法使方法参数更灵活
Jan 15 Javascript
JavaScript的jQuery库插件的简要开发指南
Aug 12 Javascript
JS实现滑动菜单效果代码(包括Tab,选项卡,横向等效果)
Sep 24 Javascript
JS前端开发判断是否是手机端并跳转操作(小结)
Feb 05 Javascript
Node.js开发第三方微信公众平台
Jun 05 Javascript
javaScript字符串工具类StringUtils详解
Dec 08 Javascript
vue.js中created方法作用
Mar 30 Javascript
vue中引用swiper轮播插件的教程详解
Aug 16 Javascript
微信小程序车牌号码模拟键盘输入功能的实现代码
Nov 11 Javascript
django简单的前后端分离的数据传输实例 axios
May 18 Javascript
JavaScript实现雪花飘落效果
Dec 27 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
单点登录 Ucenter示例分析
2013/10/29 PHP
PHP中执行cmd命令的方法
2014/10/11 PHP
smarty模板引擎基础知识入门
2015/03/30 PHP
CodeIgniter使用smtp服务发送html邮件的方法
2015/06/10 PHP
js getElementsByTagName的简写方式
2010/06/27 Javascript
jquery下异步提交表单 异步跨域提交表单
2010/11/17 Javascript
jquery中dom操作和事件的实例学习-表单验证
2011/11/30 Javascript
轻松掌握JavaScript中的Math object数学对象
2016/05/26 Javascript
BootStrap 智能表单实战系列(五) 表单依赖插件处理
2016/06/13 Javascript
深入剖析JavaScript面向对象编程
2016/07/12 Javascript
利用Vue.js+Node.js+MongoDB实现一个博客系统(附源码)
2017/04/24 Javascript
Javascript实现从小到大的数组转换成二叉搜索树
2017/06/13 Javascript
Angular2+国际化方案(ngx-translate)的示例代码
2017/08/23 Javascript
JS弹窗 JS弹出DIV并使整个页面背景变暗功能的实现代码
2018/04/21 Javascript
node.js中 redis 的安装和基本操作示例
2020/02/10 Javascript
在elementui中Notification组件添加点击事件实例
2020/11/11 Javascript
在树莓派2或树莓派B+上安装Python和OpenCV的教程
2015/03/30 Python
在Python中用keys()方法返回字典键的教程
2015/05/21 Python
python类中super()和__init__()的区别
2016/10/18 Python
python生成器,可迭代对象,迭代器区别和联系
2018/02/04 Python
python遍历文件夹找出文件夹后缀为py的文件方法
2018/10/21 Python
Django中URL的参数传递的实现
2019/08/04 Python
一行Python代码过滤标点符号等特殊字符
2019/08/12 Python
python聚类算法解决方案(rest接口/mpp数据库/json数据/下载图片及数据)
2019/08/28 Python
详解HTML5中表单验证的8种方法介绍
2016/12/19 HTML / CSS
意大利火车票和铁路通行证专家:ItaliaRail
2019/01/22 全球购物
自我评价的正确写法
2013/09/19 职场文书
小学红领巾中秋节广播稿
2014/01/13 职场文书
教师简历自我评价
2014/02/03 职场文书
租车协议书范本
2014/04/22 职场文书
运动会铅球比赛加油稿
2014/09/26 职场文书
清洁员岗位职责
2015/02/15 职场文书
贫民窟的百万富翁观后感
2015/06/09 职场文书
导游词之蜀山胜景瓦屋山
2019/11/29 职场文书
微信小程序实现录音Record功能
2021/05/09 Javascript
SQL Server数据库基本概念、组成、常用对象与约束
2022/03/20 SQL Server