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#玩多了,更喜欢这样的玩法,而对高阶组件这种方式总是感觉很奇怪)

本篇文章算是自己的一次重构笔记吧,写的只是个人的一点理解,如果有更好的办法或者疏漏的地方欢迎批评指正。

原文地址:https://www.cnblogs.com/vvjiang/p/9283006.html

时间: 2024-10-06 10:23:16

React组件重构:嵌套+继承 与 高阶组件的相关文章

【react】---react中使用装饰器(高阶组件的升级用法)

一.creact-react-app中使用装饰器 运行 npm run eject 可以让由create-react-app创建的项目的配置项暴露出来 此时,项目中多了一个config文件,并且各个配置文件已经暴露出来了.(运行npm run eject之前,保证本地没有待提交到git的文件) 安装babel插件npm install --save-dev @babel/plugin-proposal-decorators 修改package.json文件的babel配置项 "babel&quo

高阶组件的应用

高阶组件深入理解 高阶组件就是一个函数,传给它一个组件,它返回一个新的组件.新的组件使用传入的组件作为子组件.首先根据定义我们明白它就是一个函数,而且它必须有返回值,返回值是一个组件,当然这里我们高阶组件可以嵌套. 其实高阶组件就是把公用的一些部分提出来,把修改的部分以参数的形势传进去,在这里可能有人会说这那需用什么高阶组件,我自己封装一个组件也可以达到同样的效果,简单的组件在这里你可能通过封装来实现,但是我举两个例子大家在想一下怎么通过组建封装来实现: 1.antd组件的form组件, 2.我

聊聊React高阶组件(Higher-Order Components)

使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低的东西如今可不多见了啊,是个不可多得的 zhuangbility的利器,自然不可轻易错过,遂深入了解了一番. 概述 高阶组件的定义 React 官网上对高阶组件的定义: 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说,

react:高阶组件wrappedComponent

什么是高阶组件? 高阶部件是一种用于复用组件逻辑的高级技术,它并不是 React API的一部分,而是从React 演化而来的一种模式. 具体地说,高阶组件就是一个接收一个组件并返回另外一个新组件的函数! 解决什么问题? 随着项目越来越复杂,开发过程中,多个组件需要某个功能,而且这个功能和页面并没有关系,所以也不能简单的抽取成一个新的组件,但是如果让同样的逻辑在各个组件里各自实现,无疑会导致重复的代码.比如页面有三种弹窗一个有title,一个没有,一个又有右上角关闭按钮,除此之外别无它样,你总不

react高阶组件

高阶函数基本概念: 函数可以作为参数被传递, 函数可以作为返回值输出 高阶组件的基本概念: 高阶组件就是接受一个组件作为参数并返回一个新组件的函数 高级组件是一个函数,并不是组件 代理方式的高阶组件:返回的新组件类直接继承自React.Component类.新组件扮演的角色传入参数组件的一个代理,在新组件的render函数中,将被包裹组件渲染出来,除了高阶组件自己要做得工作,其余功能全都转手给了包裹的组件 代理方式的高阶组件用途: 1--操作prop         2--访问ref    3-

高阶组件

前言 本文代码浅显易懂,思想深入实用.此属于react进阶用法,如果你还不了解react,建议从文档开始看起. 我们都知道高阶函数是什么, 高阶组件其实是差不多的用法,只不过传入的参数变成了react组件,并返回一个新的组件. A higher-order component is a function that takes a component and returns a new component. 形如: const EnhancedComponent = higherOrderComp

高阶组件&amp;&amp;高阶函数(一)

antd里面的form表单方面,遇到一个高阶函数,以及高阶组件,于是看了一下这方面内容,前辈们的文章写得也非常详细,这里就稍微kobe一下 高阶函数与高阶组件 高阶函数: 高阶函数,是一种特别的函数,接受的参数为函数,返回值也是函数 成立条件,二者兼一即可 1).一类特别的函数 a).接受函数类型的参数 b).函数返回值是函数 常见的高阶函数: 2).常见 a).定时器:setTimeout()/setInterval() b).Promise:Promise(()=>{}) then(valu

【转】react的高阶组件

前言 本文代码浅显易懂,思想深入实用.此属于react进阶用法,如果你还不了解react,建议从文档开始看起. 我们都知道高阶函数是什么, 高阶组件其实是差不多的用法,只不过传入的参数变成了react组件,并返回一个新的组件. A higher-order component is a function that takes a component and returns a new component. 形如: const EnhancedComponent = higherOrderComp

react高阶组件的理解

[高阶组件和函数式编程] function hello() { console.log('hello jason'); } function WrapperHello(fn) { return function() { console.log('before say hello'); fn(); console.log('after say hello'); } } // hello 这时候等于 WrapperHello函数中返回的 匿名函数 // 在设计模式中这种操作叫做 装饰器模式 // 高