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 相关文章推荐
html中的input标签的checked属性jquery判断代码
Sep 19 Javascript
使用jquery局部刷新(jquery.load)从数据库取出数据
Jan 22 Javascript
js 针对html DOM元素操作等经验累积
Mar 11 Javascript
Bootstrap学习笔记之css组件(3)
Jun 07 Javascript
使用bootstrap typeahead插件实现输入框自动补全之问题及解决办法
Jul 07 Javascript
全面了解javascript中的错误处理机制
Jul 18 Javascript
修改Jquery Dialog 位置的实现方法
Aug 26 Javascript
vue2中使用less简易教程
Mar 27 Javascript
JS实现图片旋转动画效果封装与使用示例
Jul 09 Javascript
Vue动态路由缓存不相互影响的解决办法
Feb 19 Javascript
vuex存储token示例
Nov 11 Javascript
javascript实现时钟动画
Dec 03 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 stripos()函数及注意事项的分析
2013/06/08 PHP
解析Win7 XAMPP apache无法启动的问题
2013/06/26 PHP
ThinkPHP采用GET方式获取中文参数查询无结果的解决方法
2014/06/26 PHP
thinkphp缓存技术详解
2014/12/09 PHP
PHP动态柱状图实现方法
2015/03/30 PHP
PHP用反撇号执行外部命令
2015/04/14 PHP
PHP实现随机发放扑克牌
2020/04/21 PHP
100个不能错过的实用JS自定义函数
2014/03/05 Javascript
JavaScript中诡异的delete操作符
2015/03/12 Javascript
jQuery实现拖拽效果插件的方法
2015/03/23 Javascript
在Javascript中处理字符串之big()方法的使用
2015/06/08 Javascript
Bootstrap基本组件学习笔记之列表组(11)
2016/12/07 Javascript
详解JS对象封装的常用方式
2016/12/30 Javascript
vuejs指令详解
2017/02/07 Javascript
JavaScript 函数的定义-调用、注意事项
2017/04/16 Javascript
对vuex中getters计算过滤操作详解
2019/11/06 Javascript
VUE:vuex 用户登录信息的数据写入与获取方式
2019/11/11 Javascript
Element Steps步骤条的使用方法
2020/07/26 Javascript
[04:42]2015国际邀请赛CDEC战队晋级之路
2015/08/13 DOTA
使用grappelli为django admin后台添加模板
2014/11/18 Python
np.newaxis 实现为 numpy.ndarray(多维数组)增加一个轴
2019/11/30 Python
Python变量、数据类型、数据类型转换相关函数用法实例详解
2020/01/09 Python
Python3+PyCharm+Django+Django REST framework配置与简单开发教程
2021/02/16 Python
如何用python爬取微博热搜数据并保存
2021/02/20 Python
巴西家用小家电购物网站:Polishop
2016/08/07 全球购物
JD Sports比利时官网:英国领先的运动鞋和运动服饰零售商
2018/10/10 全球购物
导游的职业规划书范文
2013/12/27 职场文书
医德医风自我评价
2014/09/19 职场文书
个人剖析材料范文
2014/09/30 职场文书
2014年高中班主任工作总结
2014/11/08 职场文书
2016幼儿教师自荐信范文
2016/01/28 职场文书
最美劳动诗,致敬所有的劳动者!
2019/07/12 职场文书
windows下快速安装nginx并配置开机自启动的方法
2021/05/11 Servers
基于PyTorch实现一个简单的CNN图像分类器
2021/05/29 Python
多线程Spring通过@Scheduled实现定时任务
2022/05/25 Java/Android
Rust中的Struct使用示例详解
2022/08/14 Javascript