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 String对象中常用方法小结(字符串操作)
Jan 27 Javascript
JavaScript中对象property的删除方法介绍
Dec 30 Javascript
轻松学习jQuery插件EasyUI EasyUI创建树形菜单
Nov 30 Javascript
jQuery Validate初步体验(二)
Dec 12 Javascript
vue+Java后端进行调试时解决跨域问题的方式
Oct 19 Javascript
CKEditor4配置与开发详细中文说明文档
Oct 08 Javascript
Bootstrap的aria-label和aria-labelledby属性实例详解
Nov 02 Javascript
如何使用VuePress搭建一个类型element ui文档
Feb 14 Javascript
基于mpvue搭建微信小程序项目框架的教程详解
Apr 10 Javascript
ES6的解构赋值实例详解
May 06 Javascript
你或许不知道的一些npm实用技巧
Jul 04 Javascript
Javascript摸拟自由落体与上抛运动原理与实现方法详解
Apr 08 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编码规范之注释和文件结构说明
2010/07/09 PHP
Yii使用migrate命令执行sql语句的方法
2016/03/15 PHP
详解PHP如何更好的利用PHPstorm的自动提示
2017/08/18 PHP
PHP实现唤起微信支付功能
2019/02/18 PHP
JavaScript的目的分析
2007/01/05 Javascript
js出生日期 年月日级联菜单示例代码
2014/01/10 Javascript
js交换排序 冒泡排序算法(Javascript版)
2014/10/04 Javascript
原生JavaScript编写俄罗斯方块
2015/03/30 Javascript
JavaScript实现的简单幂函数实例
2015/04/17 Javascript
Javascript的this用法
2017/01/16 Javascript
完美解决jQuery的hover事件在IE中不停闪动的问题
2017/02/10 Javascript
layui导航栏实现代码
2017/05/19 Javascript
使用store来优化React组件的方法
2017/10/23 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
在angular 6中使用 less 的实例代码
2018/05/13 Javascript
浅谈在不使用ssr的情况下解决Vue单页面SEO问题(2)
2018/11/08 Javascript
微信小程序使用websocket通讯的demo,含前后端代码,亲测可用
2019/05/22 Javascript
自定义javascript验证框架示例【附源码下载】
2019/05/31 Javascript
Js参数RSA加密传输之jsencrypt.js的使用
2020/02/07 Javascript
js+canvas实现五子棋小游戏
2020/08/02 Javascript
js中复选框的取值及赋值示例详解
2020/10/18 Javascript
[33:15]2018DOTA2亚洲邀请赛3月30日 小组赛B组 VP VS Mineski
2018/03/31 DOTA
Python用list或dict字段模式读取文件的方法
2017/01/10 Python
python3利用venv配置虚拟环境及过程中的小问题小结
2018/08/01 Python
Pytest如何使用skip跳过执行测试
2020/08/13 Python
python基于win32api实现键盘输入
2020/12/09 Python
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
Java面试题及答案
2012/09/08 面试题
企业统计员岗位职责
2013/12/13 职场文书
预备党员思想汇报范文
2014/01/11 职场文书
个性发展自我评价
2014/02/11 职场文书
物流专业自荐信
2014/05/23 职场文书
文明班级申报材料
2014/12/24 职场文书
结婚当天新郎保证书
2015/05/08 职场文书
nginx 防盗链防爬虫配置详解
2021/03/31 Servers
Django程序的优化技巧
2021/04/29 Python