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验证表单第二部分
Nov 25 Javascript
extJs 下拉框联动实现代码
Apr 09 Javascript
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
Jan 13 Javascript
JS常用字符串处理方法应用总结
May 22 Javascript
微信小程序 点击控件后选中其它反选实例详解
Feb 21 Javascript
vue + vuex todolist的实现示例代码
Mar 09 Javascript
JS面向对象的程序设计相关知识小结
May 26 Javascript
在Create React App中启用Sass和Less的方法示例
Jan 16 Javascript
详解Node.js异步处理的各种写法
Jun 09 Javascript
使用zrender.js绘制体温单效果
Oct 31 Javascript
Vue简单封装axios之解决post请求后端接收不到参数问题
Feb 16 Javascript
Vue3 的响应式和以前有什么区别,Proxy 无敌?
May 20 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
学习thinkphp5.0验证类使用方法
2017/11/16 PHP
jquery监控数据是否变化(修正版)
2011/04/12 Javascript
用jQuery模拟页面加载进度条的实现代码
2011/12/19 Javascript
javascript通过class来获取元素实现代码
2013/02/20 Javascript
js取消单选按钮选中示例代码
2013/11/14 Javascript
浅析javascript中的DOM
2015/03/01 Javascript
基于BootStrap Metronic开发框架经验小结【九】实现Web页面内容的打印预览和保存操作
2016/05/12 Javascript
Vue.js第四天学习笔记
2016/12/02 Javascript
学习vue.js计算属性
2016/12/03 Javascript
node.js报错:Cannot find module 'ejs'的解决办法
2016/12/14 Javascript
Bootstrap整体框架之JavaScript插件架构
2016/12/15 Javascript
React中jquery引用的实现方法
2017/09/12 jQuery
解决微信浏览器缓存站点入口文件(IIS部署Vue项目)
2019/06/17 Javascript
新手快速入门JavaScript装饰者模式与AOP
2019/06/24 Javascript
详解从vue-loader源码分析CSS Scoped的实现
2019/09/23 Javascript
vue 组件内获取actions的response方式
2019/11/08 Javascript
[01:31](回顾)杀出重围,决战TI之巅
2014/07/01 DOTA
[02:04]2018DOTA2亚洲邀请赛Secret赛前采访
2018/04/03 DOTA
Python计算三角函数之asin()方法的使用
2015/05/15 Python
约瑟夫问题的Python和C++求解方法
2015/08/20 Python
Python入门_浅谈for循环、while循环
2017/05/16 Python
python方向键控制上下左右代码
2018/01/20 Python
解决python3 网络请求路径包含中文的问题
2018/05/10 Python
安装docker-compose的两种最简方法
2019/07/30 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
HTML5 新事件 小结
2009/07/16 HTML / CSS
AmazeUI中模态框的实现
2020/08/19 HTML / CSS
彪马美国官网:PUMA美国
2017/03/09 全球购物
COACH德国官方网站:纽约现代奢侈品牌,1941年
2018/06/09 全球购物
Linux文件操作命令都有哪些
2016/07/23 面试题
幼教毕业生自我鉴定
2014/01/12 职场文书
团队会宣传标语
2014/10/09 职场文书
敲诈同学钱财检讨书范文
2014/11/18 职场文书
世界地球日活动总结
2015/02/09 职场文书
公司2015年终工作总结
2015/05/26 职场文书
一封真诚的自荐信帮你赢得机会
2019/05/07 职场文书