React组件重构:嵌套+继承 与 高阶组件
前言
在最近做的一个react项目中,遇到了一个比较典型的需要重构的场景:提取两个组件中共同的部分。
最开始通过使用嵌套组件和继承的方式完成了这次重构。
但是后来又用高阶组件重新写了一遍,发现更好一点。
在这里记录下这两种方式以便之后参考和演进。
本次重构的场景
因为场景涉及到具体的业务,所以我现在将它简化为一个简单的场景。
现在有两个黑色箱子,箱子上都有一个红色按钮,A箱子充满气体,按了按钮之后箱子里面气体变红,B箱子充满泥土,按了之后箱子里面泥土变红。
那么现在上一个简单的重构前代码:
BoxA.jsx
import React, { Component, PropTypes } from 'react'
class BoxA extends Component {
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
handleShake=()=>{
/* 摇动后气体没声音 */
}
render() {
return (
/* 这里面当然没有onShake这种事件,理解意思就行了 */
<div style={{backgroundColor:'black'}} onShake={this.handleShake}>
<button onClick={this.handleClick} style={{backgroundColor:'red'}}></button>
<div>
/* 气体组件,没毛病 */
<气体 color={this.state.color} />
</div>
</div>
)
}
}
BoxB.jsx
import React, { Component, PropTypes } from 'react'
class BoxB extends Component {
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
handleShake=()=>{
/* 摇动后泥土有声音 */
}
render() {
return (
<div style={{backgroundColor:'black'}} onShake={this.handleShake}>
<button onClick={this.handleClick} style={{backgroundColor:'red'}}></button>
<div>
<泥土 color={this.state.color} />
</div>
</div>
)
}
}
使用嵌套组件进行重构
看看上面的代码,即使在业务简化的情况下都有很多重复的,所以得重构。
对于这种很明显的箱子类问题,一般都会采用嵌套组件的方式重构。
Box.jsx
import React, { Component, PropTypes } from 'react'
class Box extends Component {
static propTypes = {
children: PropTypes.node,
onClick: PropTypes.func,
onShake: PropTypes.func
}
render() {
return (
<div style={{backgroundColor:'black'}} onShake={this.props.onShake}>
<button onClick={this.props.onClick} style={{backgroundColor:'red'}}></button>
<div>
{this.children}
</div>
</div>
)
}
}
BoxA.jsx
import React, { Component, PropTypes } from 'react'
import Box from './Box.jsx'
class BoxA extends Component {
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
handleShake=()=>{
/* 摇动后气体没声音 */
}
render() {
return (
<Box onClick={this.handleClick} onShake={this.props.handleShake}>
<气体 color={this.state.color} />
</Box>
)
}
}
BoxB.jsx
import React, { Component, PropTypes } from 'react'
class BoxB extends Component {
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
handleShake=()=>{
/* 摇动后泥土有声音 */
}
render() {
return (
<Box onClick={this.handleClick} onShake={this.props.handleShake}>
<泥土 color={this.state.color} />
</Box>
)
}
}
使用继承组件的方式进行重构
对于很多场景而言,使用了嵌套组件后,可能就不需要或者没法进一步进行组件提炼了。
然而完成这波操作后,我们发现嵌套组件BoxA和BoxB依然存在重复代码,即按下按钮变红这部分代码。
这部分代码可以使用嵌套组件与被嵌套组件的通信机制来处理,技术上而言依然可以将这部分代码用嵌套组件的方式来解决。
但是为了保证组件的单一职责,即箱子就是个带红色按钮可以摇动的箱子,我们不知道里面以后会放什么进去,就不能说不管以后里面放什么,只要我一按红色按钮,里面的物质都会变红。
这部分代码肯定是不能放在嵌套组件Box里,因为它直接操作着被嵌套的内容。
那么在这里我们可以使用继承组件的方式。
Box.jsx
import React, { Component, PropTypes } from 'react'
class Box extends Component {
static propTypes = {
children: PropTypes.node,
onClick: PropTypes.func,
onShake: PropTypes.func
}
render() {
return (
<div style={{backgroundColor:'black'}} onShake={this.props.onShake}>
<button onClick={this.props.onClick} style={{backgroundColor:'red'}}></button>
<div>
{this.children}
</div>
</div>
)
}
}
BasicBox.jsx
import React, { Component, PropTypes } from 'react'
class BasicBox extends Component {
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
}
BoxA.jsx
import React, { Component, PropTypes } from 'react'
import Box from './Box.jsx'
class BoxA extends BasicBox {
handleShake=()=>{
/* 摇动后气体没声音 */
}
render() {
return (
<Box onClick={this.handleClick} onShake={this.props.handleShake}>
<气体 color={this.state.color} />
</Box>
)
}
}
BoxB.jsx
import React, { Component, PropTypes } from 'react'
class BoxB extends BasicBox {
handleShake=()=>{
/* 摇动后泥土有声音 */
}
render() {
return (
<Box onClick={this.handleClick} onShake={this.props.handleShake}>
<泥土 color={this.state.color} />
</Box>
)
}
}
通过修改后的代码,就可以将BoxA和BoxB中相同的部分提取到BasicBox中。
这样我们相当于将一个功能块提取了出来,你可以继承BasicBox(这个命名可能不好,容易引起混淆),如果不使用state的值也完全没有任何问题。
但是这样做也许会带了一些别的问题。
我们自己去看这段代码的时候其实不难理解,不过之后让其他人对这块代码做修改时,后来的人就会感到奇怪,BoxA中突然间使用了一个不知道从哪里来的handleClick。
使用高阶组件进行重构
为了解决上面的问题,后来又使用高阶组件的方式玩了一遍:
hocBox.jsx
import React, { Component, PropTypes } from 'react'
hocBox=(WrappedComponent)=>{
return class Box extends Component{
static propTypes = {
onShake: PropTypes.func
}
state={
color:'black'
}
handleClick=()=>{
this.setState({
color:'red'
})
}
render() {
return (
<div style={{backgroundColor:'black'}} onShake={this.props.handleShake}>
<button onClick={this.handleClick} style={{backgroundColor:'red'}}></button>
<div>
<WrappedComponent color={this.state.color} />
</div>
</div>
)
}
}
}
BoxA.jsx
import React, { Component, PropTypes } from 'react'
import Box from './hocBox.jsx'
const 气体WithBtnBox=hocBox(气体)
class BoxA extends BasicBox {
handleShake=()=>{
/* 摇动后气体没声音 */
}
render() {
return (
<气体WithBtnBox onShake={this.handleShake} />
)
}
}
BoxB.jsx
import React, { Component, PropTypes } from 'react'
import Box from './hocBox.jsx'
const 泥土WithBtnBox=hocBox(泥土)
class BoxA extends BasicBox {
handleShake=()=>{
/* 摇动后泥土有声音 */
}
render() {
return (
<泥土WithBtnBox onShake={this.handleShake} />
)
}
}
高阶组件的使用就像设计模式中的装饰者模式(Decorator Pattern)。
总结
以上的两种方式中,高阶组件的方式对于后来者在修改上更友好一点。
但是用嵌套+继承的方式理解起来其实更容易一点,特别是去重构一个复杂的组件时,通过这种方式往往更快,拆分起来更容易。(我个人更倾向于这种,不知道是不是C#玩多了,更喜欢这样的玩法,而对高阶组件这种方式总是感觉很奇怪)
本篇文章算是自己的一次重构笔记吧,写的只是个人的一点理解,如果有更好的办法或者疏漏的地方欢迎批评指正。
React组件重构:嵌套+继承 与 高阶组件的更多相关文章
- 函数式编程与React高阶组件
相信不少看过一些框架或者是类库的人都有印象,一个函数叫什么creator或者是什么什么createToFuntion,总是接收一个函数,来返回另一个函数.这是一个高阶函数,它可以接收函数可以当参数,也 ...
- React躬行记(10)——高阶组件
高阶组件(High Order Component,简称HOC)不是一个真的组件,而是一个没有副作用的纯函数,以组件作为参数,返回一个功能增强的新组件,在很多第三方库(例如Redux.Relay等)中 ...
- 聊聊React高阶组件(Higher-Order Components)
使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...
- 当初要是看了这篇,React高阶组件早会了
当初要是看了这篇,React高阶组件早会了. 概况: 什么是高阶组件? 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说 ...
- react:高阶组件wrappedComponent
什么是高阶组件? 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说,高阶组件就是一个接收一个组件并返回另外一个新组件的函 ...
- React 之 高阶组件的理解
1.基本概念 高阶组件是参数为组件,返回值为新组件的函数. 2.举例说明 ① 装饰工厂模式 组件是 react 中的基本单元,组件中通常有一些逻辑(非渲染)需要复用处理.这里我们可以用高阶组件对组件内 ...
- React 高阶组件浅析
高阶组件的这种写法的诞生来自于社区的实践,目的是解决一些交叉问题(Cross-Cutting Concerns).而最早时候 React 官方给出的解决方案是使用 mixin .而 React 也在官 ...
- 8、react 高阶组件
1.高阶组件:封装 高阶组件使用得是react得一种模式,增强现有组件得功能 一个高阶组件就是一个函数,这个函数接收得是组件类作为参数得,并且返回得是一个新组件,再返回得新组件中有输入参数组件不具备得 ...
- react高阶组件的一些运用
今天学习了react高阶组件,刚接触react学习起来还是比较困难,和大家分享一下今天学习的知识吧,另外缺少的地方欢迎补充哈哈 高阶组件(Higher Order Components,简称:HOC) ...
随机推荐
- HandyEditor 富文本编辑器整合到python flask项目中
1.下载HandyEditor,地址http://he.catfish-cms.com/ 2.解压后的文件名HandyEditor-master改为HandyEditor,文件夹里的文件如下 3.将H ...
- SQLOS任务调度算法
前些天在处理一个SQL Server LATCH导致的数据库停止响应问题时,遇到了一些需要SQLOS调度知识解决的问题,正好以前看过一篇官网的文章,在这里稍作修改贴出来. 原文网址如下: https: ...
- MongoDB数据库简单操作
之前学过的有mysql数据库,现在我们学习一种非关系型数据库 一.简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数 ...
- NSMutableArray 增删操作测试
NSMutableArray *testArray = [NSMutableArray array]; [testArray addObject:"]; [testArray addObje ...
- C++实现第三方资源释放与载入过程(以DLL为例)
简介 我们经常看见有一些程序开始执行时会释放一些文件,以便于后续操作.例如一些病毒为了便于传播和隐藏,经常把一些需要用的动态库或是驱动文件打包进一个可执行文件中,再由需要使用的时候,再临时释放和加载. ...
- Linux:固定 ip
默认情况下,安装完操作系统时,ip是采用dhcp来动态分配的.通常我们需要将其固定下来. 不然 每次系统重启后,ip都会变动,这样会给日常工作带来不必要的麻烦的. 下面就是在rhel .centos ...
- xp,windows7,windows8,windows10那个系统好用些
Windows XP:这曾经是微软史上最好的.最受欢迎.最受好评的可以说空前绝后的系统,虽然,XP系统对电脑配置的要求很低,基本现在所有的电脑都支持安装该系统,可它太老旧了,到2014年4-5月份微软 ...
- ASP.NET -- WebForm -- HttpResponse 类的方法和属性
ASP.NET -- WebForm -- HttpResponse 类的方法和属性 1. HttpResponse 类的方法 (1) AddCacheDependency: 将一组缓存依赖项与响应关 ...
- June. 20 2018, Week 25th. Wednesday
Be brave. Take risks. Nothing can substitute experience. 要敢于冒险,你的经历是无可替代的. From Paulo Coelho. Each s ...
- March 10th, 2018 Week 10th Saturday
All good things must come to an end. 好景无常. Love is when the other person's happiness is more importa ...