Component-based Architecture — A Case Study

How splitting the component into smaller ones reduces the complexity

Rui Vilela
Beamery Hacking Talent
3 min readJun 13, 2018

--

Rui Vilela | Front-end Engineer, Engineering

This is based on a real code example, but the code and names where changed for the purpose of making the example more understandable and general.

Problem

We wanted to use a third party Library for an UI element called AwesomeList. This UI library allows you to pass an array of objects through a property called ‘renderItems’ and it will create you a list with the array of Objects you pass to it. In order to achieve that the code inside our component would look like following

this.props.items = [{name:’john’}, {name:’trevor’}]

<AwesomeList
renderItems={
({index}) => (
<div> this.props.items[index].name </div>
)
}
/>

The example above is quite straight forward, let’s complicate this a bit more. We want to add an interactive aspect to how our AwesomeList, we want that when you click on the item in the list, the text gets crossed out and if you click on it again it should turn back to normal. Without applying the component based architecture logic, we would want to do all these operations in the same component. So for that we need to create an array of objects that stores the values that are selected and removes them from that list when we click the second time. (we’ll be using lodash to manipulate our arrays).

const selected = [] // this needs to be globalreturn(
<AwesomeList
renderItems={
({index}) => {
const crossed = _.find(
selected,
item => item === this.props.items[index]
? 'crossedOut' : 'backToNormal'
)
return (
<div
className={crossed}
onClick={this.crossOut(this.props.items[index].name)}
>
this.props.items[index].name
</div>
)
}
}
/>
)

Our this.crossOut method should perform the following actions:

  • When you click on the item it searches our selected array
  • If it is in the array, remove it from the array
  • If it is not in the array add it

So our this.crossOut method would look like this

crossOut = (item) => {
const index = _.findIndex(
selected,
selectedItem => selectedItem === item
)

index === -1 ? selected.push(item) : selected.pop(item);
}

This should work, but the problem with this solution is:

  • The real code example, also put into consideration that you could pre determine the items you wanted to crossOut.
  • Performing operations of manipulation arrays get messy really quickly
  • In general the code is not really readable, especially if you need to add more features, it will get really messy.

Solution

The solution to avoid manipulating arrays, is to use a principle of the component based architecture where we can scope in our components. This means creating a sub component. (a component that contains another component).

<AwesomeList 
renderItems={
({item}) => (
<MyNewSubComponent
item={item}
/>
}
/>

This way, when we create our MyNewSubComponent, inside of it we aren’t dealing with an array anymore, but instead with the actual Item object which is something that is more manageable and less complex.

In this new subComponent using mobx our this.crossOut method would look like :

crossOut = () => (
this.selected = !this.selected
)

And our return would look something like this:

const className = this.selected ? 'crossedOut' : 'backToNormal';return(
<div className={className}> {this.props.item.name} </div>
)

--

--