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无限树状列表实现代码
Jan 11 Javascript
JS 添加网页桌面快捷方式的代码详细整理
Dec 27 Javascript
Javascript的时间戳和php的时间戳转换注意事项
Apr 12 Javascript
js加入收藏夹代码(兼容ie/ff/op)
May 16 Javascript
jQuery实现动态表单验证时文本框抖动效果完整实例
Aug 21 Javascript
怎么限制input的text里输入的值只能是数字(正则、js)
May 16 Javascript
基于Bootstrap里面的Button dropdown打造自定义select
May 30 Javascript
用AngularJS来实现监察表单按钮的禁用效果
Nov 02 Javascript
JS实现颜色梯度与渐变效果完整实例
Dec 30 Javascript
JQuery表单元素取值赋值方法总结
May 12 jQuery
原生JS实现拖拽效果
Dec 04 Javascript
Vue3如何理解ref toRef和toRefs的区别
Feb 18 Vue.js
详解前端路由实现与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中对数据库操作的封装
2006/10/09 PHP
ubuntu 编译安装php 5.3.3+memcache的方法
2010/08/05 PHP
php 记录进行累加并显示总时长为秒的结果
2011/11/04 PHP
基于Zend的Config机制的应用分析
2013/05/02 PHP
PHP使Laravel为JSON REST API返回自定义错误的问题
2018/10/16 PHP
关于laravel-admin ueditor 集成并解决刷新的问题
2019/10/21 PHP
一页面多XMLHttpRequest对象
2007/01/22 Javascript
基于jquery库的tab新形式使用
2012/11/16 Javascript
js处理json以及字符串的比较等常用操作
2013/09/08 Javascript
JavaScript中的undefined学习总结
2013/11/30 Javascript
详解Angular2中的编程对象Observable
2016/09/17 Javascript
浅谈webpack编译vue项目生成的代码探索
2017/12/11 Javascript
从setTimeout看js函数执行过程
2017/12/19 Javascript
jq.ajax+php+mysql实现关键字模糊查询(示例讲解)
2018/01/02 Javascript
Webpack path与publicPath的区别详解
2018/05/03 Javascript
Vue父子组件之间的通信实例详解
2018/09/28 Javascript
在Vue中创建可重用的 Transition的方法
2020/06/02 Javascript
python单例模式实例解析
2018/08/28 Python
Python3 实现串口两进程同时读写
2019/06/12 Python
Python Django 前后端分离 API的方法
2019/08/28 Python
基于python 等频分箱qcut问题的解决
2020/03/03 Python
python 绘制国旗的示例
2020/09/27 Python
使用jTopo给Html5 Canva中绘制的元素添加鼠标事件
2014/05/15 HTML / CSS
S’well Bottle保温杯官网:绝缘不锈钢水瓶
2018/05/09 全球购物
优秀中专生推荐信
2013/11/17 职场文书
农救科工作职责
2013/11/27 职场文书
大学生毕业鉴定
2014/01/31 职场文书
安全演讲稿大全
2014/05/09 职场文书
巴西世界杯32强口号
2014/06/05 职场文书
感恩教育月活动总结
2014/07/07 职场文书
2014财务人员自我评价范文
2014/09/21 职场文书
办理护照工作证明
2014/10/10 职场文书
晚自修旷课检讨书怎么写
2014/11/17 职场文书
Python中的套接字编程是什么?
2021/06/21 Python
MySQL去除重叠时间求时间差和的实现
2021/08/23 MySQL
解决 redis 无法远程连接
2022/05/15 Redis