SoFunction
Updated on 2025-03-10

React component reconstruction Nesting + inheritance and detailed explanation of advanced components

Preface

In a recent react project, I encountered a typical scenario that needs to be refactored: extracting the common parts of the two components.

This reconstruction was initially completed by using nested components and inheritance.

But later I rewrite it with advanced components and found that it was a little better.

These two methods are recorded here for later reference and evolution.

The scene of this reconstruction

Because the scenario involves specific business, I'm now simplifying it into a simple scenario.

There are now two black boxes, and there is a red button on the box. Box A is filled with gas. After pressing the button, the gas in the box turns red, box B is filled with soil. After pressing it, the soil in the box turns red.

So now, the previous simple pre-refactoring code:


import React, { Component, PropTypes } from 'react'

class BoxA extends Component {
 state={
 color:'black'
 }

 handleClick=()=>{
 ({
  color:'red'
 })
 }

 handleShake=()=>{
 /* No sound in the gas after shaking */
 }

 render() {
 return (
  /* Of course there is no event like onShake in it, just understand the meaning */
  <div style={{backgroundColor:'black'}} onShake={}>
   <button onClick={} style={{backgroundColor:'red'}}></button>
   <div>
   /* Gas ​​components, no problem */
   <gas color={} />
   </div>
  </div>
 )
 }
}


import React, { Component, PropTypes } from 'react'

class BoxB extends Component {
 state={
 color:'black'
 }
 handleClick=()=>{
 ({
  color:'red'
 })
 }

 handleShake=()=>{
 /* There is a sound after shaking */
 }

 render() {
 return (
  <div style={{backgroundColor:'black'}} onShake={}>
   <button onClick={} style={{backgroundColor:'red'}}></button>
   <div>
   <soil color={} />
   </div>
  </div>
 )
 }
}

Refactoring with nested components

Look at the above code, even if the business is simplified, there are many repetitions, so it needs to be refactored.

For this very obvious box-like problem, nested components are generally refactored.

import React, { Component, PropTypes } from 'react'

class Box extends Component {

 static propTypes = {
 children: ,
 onClick: ,
 onShake: 
 }

 render() {
 return (
  <div style={{backgroundColor:'black'}} onShake={}>
   <button onClick={} style={{backgroundColor:'red'}}></button>
   <div>
   {}
   </div>
  </div>
 )
 }
}


import React, { Component, PropTypes } from 'react'
import Box from './'

class BoxA extends Component {
 state={
 color:'black'
 }

 handleClick=()=&gt;{
 ({
  color:'red'
 })
 }

 handleShake=()=&gt;{
 /* No sound in the gas after shaking */
 }

 render() {
 return (
  &lt;Box onClick={} onShake={}&gt;
  &lt;gas color={} /&gt;
  &lt;/Box&gt;
 )
 }
}


import React, { Component, PropTypes } from 'react'

class BoxB extends Component {
 state={
 color:'black'
 }
 handleClick=()=&gt;{
 ({
  color:'red'
 })
 }

 handleShake=()=&gt;{
 /* There is a sound after shaking */
 }

 render() {
 return (
  &lt;Box onClick={} onShake={}&gt;
  &lt;soil color={} /&gt;
  &lt;/Box&gt;
 )
 }
}

Refactoring using inherited components

For many scenarios, after using nested components, it may not be necessary or impossible to further refine the component.

However, after completing this wave of operations, we found that there are still duplicate codes in nested components BoxA and BoxB, that is, the part of the code will turn red when pressing the button.

This part of the code can be processed using the communication mechanism between nested components and nested components. Technically, this part of the code can still be solved in the form of nested components.

However, in order to ensure the single responsibility of the component, that is, the box is a box with a red button that can be shaken. We don’t know what will be put in in the future, so we can’t say that no matter what is placed in the future, as long as I press the red button, the substance inside will turn red.

This part of the code must not be placed in the nested component box, because it directly operates on the nested content.

Then here we can use the inheritance component method.


import React, { Component, PropTypes } from 'react'

class Box extends Component {
 static propTypes = {
 children: ,
 onClick: ,
 onShake: 
 }

 render() {
 return (
  <div style={{backgroundColor:'black'}} onShake={}>
   <button onClick={} style={{backgroundColor:'red'}}></button>
   <div>
   {}
   </div>
  </div>
 )
 }
}


import React, { Component, PropTypes } from 'react'
class BasicBox extends Component {
 state={
 color:'black'
 }

 handleClick=()=>{
 ({
  color:'red'
 })
 }
}


import React, { Component, PropTypes } from 'react'
import Box from './'

class BoxA extends BasicBox {
 handleShake=()=&gt;{
 /* No sound in the gas after shaking */
 }

 render() {
 return (
  &lt;Box onClick={} onShake={}&gt;
  &lt;gas color={} /&gt;
  &lt;/Box&gt;
 )
 }
}


import React, { Component, PropTypes } from 'react'

class BoxB extends BasicBox {
 handleShake=()=&gt;{
 /* There is a sound after shaking */
 }

 render() {
 return (
  &lt;Box onClick={} onShake={}&gt;
  &lt;soil color={} /&gt;
  &lt;/Box&gt;
 )
 }
}

Through the modified code, the same parts in BoxA and BoxB can be extracted into BasicBox.

In this way, we are equivalent to extracting a function block, you can inherit BasicBox (this name may be bad and easily confusing), and there will be no problem without using the value of state.

But doing so may bring some other problems.

It is not difficult to understand when we look at this code ourselves, but when others modify this code later, people will be surprised that a handleClick suddenly used in BoxA that didn't know where it came from.

Refactoring using advanced components

In order to solve the above problem, I later played it with the method of higher-level components:


import React, { Component, PropTypes } from 'react'

hocBox=(WrappedComponent)=>{
 return class Box extends Component{
  static propTypes = {
  onShake: 
  }

  state={
  color:'black'
  }

  handleClick=()=>{
  ({
   color:'red'
  })
  }

  render() {
  return (
   <div style={{backgroundColor:'black'}} onShake={}>
    <button onClick={} style={{backgroundColor:'red'}}></button>
    <div>
    <WrappedComponent color={} />
    </div>
   </div>
  )
  }
 }
}


import React, { Component, PropTypes } from 'react'
import Box from './'


const gasWithBtnBox=hocBox(gas)
class BoxA extends BasicBox {
 handleShake=()=&gt;{
 /* No sound in the gas after shaking */
 }

 render() {
 return (
  &lt;gasWithBtnBox onShake={} /&gt;
 )
 }
}


import React, { Component, PropTypes } from 'react'
import Box from './'

const soilWithBtnBox=hocBox(soil)
class BoxA extends BasicBox {
 handleShake=()=&gt;{
 /* There is a sound after shaking */
 }

 render() {
 return (
  &lt;soilWithBtnBox onShake={} /&gt;
 )
 }
}

The use of advanced components is like the Decorator Pattern in the design pattern.

Summarize

Among the above two methods, the advanced component method is more friendly to later generations in terms of modification.
However, it is actually easier to understand by nesting + inheritance, especially when refactoring a complex component, this method is often faster and easier to split. (I personally prefer this kind of thing. I don’t know if I have played C# too much, and I prefer this way of playing it. I always feel strange about the method of high-level components)
This article is my own reconstructed notes. It only writes a little personal understanding. If there is a better way or omission, you are welcome to criticize and correct me.

Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.