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 19 Javascript
javascript offsetX与layerX区别
Mar 12 Javascript
巧用jquery解决下拉菜单被Div遮挡的相关问题
Feb 13 Javascript
setInterval计时器不准的问题解决方法
May 08 Javascript
JavaScript实现图片DIV竖向滑动的方法
Apr 25 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
Sep 17 Javascript
chrome调试javascript详解
Oct 21 Javascript
JS代码实现根据时间变换页面背景效果
Jun 16 Javascript
基于jQuery和hwSlider实现内容左右滑动切换效果附源码下载(一)
Jun 22 Javascript
JS实现点击循环切换显示内容的方法
Oct 19 Javascript
JavaScript原型链与继承操作实例总结
Aug 24 Javascript
vue基于better-scroll实现左右联动滑动页面
Jun 30 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实现的短网址算法分享
2014/06/20 PHP
PHP分页类集锦
2014/11/18 PHP
PHP实现导出带样式的Excel
2016/08/28 PHP
PHP创建多级目录的两种方法
2016/10/28 PHP
PHP时间日期增减操作示例【date strtotime实现加一天、加一月等操作】
2018/12/21 PHP
jQuery Ajax请求状态管理器打包
2012/05/03 Javascript
.net,js捕捉文本框回车键事件的小例子(兼容多浏览器)
2013/03/11 Javascript
javascript loadScript异步加载脚本示例讲解
2013/11/14 Javascript
Angularjs 基础入门
2014/12/26 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
2015/08/31 Javascript
浅析nodejs实现Websocket的数据接收与发送
2015/11/19 NodeJs
深入浅析JavaScript中的Function类型
2016/07/09 Javascript
JavaScript比较当前时间是否在指定时间段内的方法
2016/08/02 Javascript
jQuery购物网页经典制作案例
2016/08/19 Javascript
详谈js中window.location.search的用法和作用
2017/02/13 Javascript
JavaScript实现瀑布流图片效果
2017/06/30 Javascript
深入理解Vue-cli搭建项目后的目录结构探秘
2017/07/13 Javascript
javascript实现文字无缝滚动效果
2017/08/26 Javascript
javascript基于定时器实现进度条功能实例
2017/10/13 Javascript
JS实现点击li标签弹出对应的索引功能【案例】
2019/02/18 Javascript
浅谈监听单选框radio改变事件(和layui中单选按钮改变事件)
2019/09/10 Javascript
Python记录详细调用堆栈日志的方法
2015/05/05 Python
在Mac OS系统上安装Python的Pillow库的教程
2015/11/20 Python
深入理解Python对Json的解析
2017/02/14 Python
python opencv 直方图反向投影的方法
2018/02/24 Python
纯css3使用vw和vh实现自适应的方法
2018/02/09 HTML / CSS
详解h5页面在不同ios设备上的问题总结
2019/03/01 HTML / CSS
MYSQL支持事务吗
2013/08/09 面试题
创业计划书中包含的9个方面
2013/12/26 职场文书
家长对老师的评语
2014/04/18 职场文书
高等教育学专业自荐书
2014/06/17 职场文书
体育系毕业生自荐信
2014/06/28 职场文书
放飞理想演讲稿
2014/09/09 职场文书
人事文员岗位职责
2015/02/04 职场文书
CSS3 菱形拼图实现只旋转div 背景图片不旋转功能
2021/03/30 HTML / CSS
浅谈MySQL之浅入深出页原理
2021/06/23 MySQL