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.validate分组验证代码
Mar 17 Javascript
js字符串截取函数substr substring slice使用对比
Nov 27 Javascript
Node.js实现的简易网页抓取功能示例
Dec 05 Javascript
jQuery on()绑定动态元素出现的问题小结
Feb 19 Javascript
AngularJS+Bootstrap实现多文件上传与管理
Nov 08 Javascript
javascript实现循环广告条效果
Dec 12 Javascript
对angularjs框架下controller间的传值方法详解
Oct 08 Javascript
如何能分清npm cnpm npx nvm
Jan 17 Javascript
微信小程序实现的一键拨号功能示例
Apr 24 Javascript
详解vue项目中实现图片裁剪功能
Jun 07 Javascript
微信小程序列表时间戳转换实现过程解析
Oct 12 Javascript
element-ui table行点击获取行索引(index)并利用索引更换行顺序
Feb 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
php把大写命名转换成下划线分割命名
2015/04/27 PHP
PHP自定义错误处理的方法分析
2018/12/19 PHP
PHP的curl函数的用法总结
2019/02/14 PHP
PHP递归算法的简单实例
2019/02/28 PHP
php面向对象基础详解【星际争霸游戏案例】
2020/01/23 PHP
在JavaScript中使用inline函数的问题
2007/03/08 Javascript
javascript实现获取浏览器版本、操作系统类型
2015/01/29 Javascript
2则自己编写的jQuery特效分享
2015/02/26 Javascript
Vue 过渡(动画)transition组件案例详解
2017/01/22 Javascript
JS简单实现父子窗口传值功能示例【未使用iframe框架】
2017/09/20 Javascript
捕获未处理的Promise错误方法
2017/10/13 Javascript
微信小程序 scroll-view实现锚点滑动的示例
2017/12/06 Javascript
解决Vue watch里调用方法的坑
2020/11/07 Javascript
python中使用序列的方法
2015/08/03 Python
Request的中断和ErrorHandler实例解析
2018/02/12 Python
Selenium的使用详解
2018/10/19 Python
python多线程调用exit无法退出的解决方法
2019/02/18 Python
python地震数据可视化详解
2019/06/18 Python
python 的 scapy库,实现网卡收发包的例子
2019/07/23 Python
python retrying模块的使用方法详解
2019/09/25 Python
python可视化实现KNN算法
2019/10/16 Python
详解Python中如何将数据存储为json格式的文件
2020/11/18 Python
巴西24小时在线药房:Drogasil
2020/06/20 全球购物
在Java开发中如何选择使用哪种集合类
2016/08/09 面试题
大学生职业生涯设计书
2014/01/02 职场文书
学校介绍信范文
2014/01/14 职场文书
餐饮管理自我介绍信
2014/01/15 职场文书
个人简历中自我评价
2014/02/11 职场文书
开展批评与自我批评发言材料
2014/05/15 职场文书
农村环境卫生倡议书
2015/04/29 职场文书
企业培训简报范文
2015/07/20 职场文书
解除租赁合同协议书
2016/03/21 职场文书
加薪申请书应该这样写!
2019/07/04 职场文书
python实现股票历史数据可视化分析案例
2021/06/10 Python
Python并发编程实例教程之线程的玩法
2021/06/20 Python
7个关于Python的经典基础案例
2021/11/07 Python