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脚本
Dec 03 Javascript
JavaScript检查某个function是否是原生代码的方法
Aug 20 Javascript
JS使用post提交的两种方式
Dec 03 Javascript
简单的jQuery banner图片轮播实例代码
Mar 04 Javascript
Bootstrap每天必学之响应式导航、轮播图
Apr 25 Javascript
在线引用最新jquery文件的实现方法
Aug 26 Javascript
javascript 解决浏览器不支持的问题
Sep 24 Javascript
详解jQuery插件开发方式
Nov 22 Javascript
vue-router跳转页面的方法
Feb 09 Javascript
利用node.js实现反向代理的方法详解
Jul 24 Javascript
es6学习之解构时应该注意的点
Aug 29 Javascript
VUE中使用HTTP库Axios方法详解
Feb 05 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定时自动生成静态HTML的实现代码
2010/06/20 PHP
一个非常完美的读写ini格式的PHP配置类分享
2015/02/12 PHP
PHP简单实现解析xml为数组的方法
2018/05/02 PHP
php微信开发之谷歌测距
2018/06/14 PHP
Yii2处理密码加密及验证的方法
2019/05/12 PHP
Laravel等框架模型关联的可用性浅析
2019/12/15 PHP
PHPExcel实现的读取多工作表操作示例
2020/04/14 PHP
js特殊字符转义介绍
2013/11/05 Javascript
自己封装的javascript事件队列函数版
2014/06/12 Javascript
处理文本部分内容的TextRange对象应用实例
2014/07/29 Javascript
javascript 10进制和62进制的相互转换
2014/07/31 Javascript
第一次接触神奇的Bootstrap菜单和导航
2016/08/01 Javascript
使用JavaScript判断手机浏览器是横屏还是竖屏问题
2016/08/02 Javascript
详解vue2.0的Element UI的表格table列时间戳格式化
2017/06/13 Javascript
React学习笔记之事件处理(二)
2017/07/02 Javascript
详解vue渲染函数render的使用
2017/12/12 Javascript
使用vue打包时vendor文件过大或者是app.js文件很大的问题
2018/06/29 Javascript
在vue项目中优雅的使用SVG的方法实例详解
2018/12/03 Javascript
nodejs 递归拷贝、读取目录下所有文件和目录
2019/07/18 NodeJs
微信小程序获取公众号文章列表及显示文章的示例代码
2020/03/10 Javascript
Element Cascader 级联选择器的使用示例
2020/07/27 Javascript
vue中是怎样监听数组变化的
2020/10/24 Javascript
[50:01]Ti4 冒泡赛第二天 NEWBEE vs Titan
2014/07/15 DOTA
[50:50]完美世界DOTA2联赛PWL S3 Galaxy Racer vs Phoenix 第一场 12.10
2020/12/13 DOTA
Python中的is和==比较两个对象的两种方法
2017/09/06 Python
用python处理图片之打开\显示\保存图像的方法
2018/05/04 Python
使用python脚本自动创建pip.ini配置文件代码实例
2019/09/20 Python
Python控制台实现交互式环境执行
2020/06/09 Python
django 获取字段最大值,最新的记录操作
2020/08/09 Python
ffmpeg+Python实现B站MP4格式音频与视频的合并示例代码
2020/10/21 Python
印度最大的网上花店:Ferns N Petals(鲜花、礼品和蛋糕)
2017/10/16 全球购物
英国在线药房和在线药剂师:Chemist 4 U
2020/01/05 全球购物
个人求职信范文分享
2014/01/06 职场文书
纪念九一八事变演讲稿:忘记意味着背叛
2014/09/14 职场文书
浅谈PHP7中的一些小技巧
2021/05/29 PHP
TensorFlow中tf.batch_matmul()的用法
2021/06/02 Python