欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React组件重构之嵌套+继承及高阶组件详解

程序员文章站 2023-10-30 08:43:46
前言 在最近做的一个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#玩多了,更喜欢这样的玩法,而对高阶组件这种方式总是感觉很奇怪)
本篇文章算是自己的一次重构笔记吧,写的只是个人的一点理解,如果有更好的办法或者疏漏的地方欢迎批评指正。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。