Keep it Silly, Stupid
Tags: react, webdev, frontend, typescript
Published: 2024-03-31 15:46:27

If you've entered this article because you think I misspelt the KISS principle, I'm sorry, but you've been clickbaited.

Let me explain myself.

The desing of reusable and flexible components has almost become a form of art (like any part of development actually).

However, it's easy to fall into the trap of creating overly complex components that are tightly coupled to specific use cases.

My take here is to **keep them silly**. That is, making them as dumb as possible. By doing so, we can maximize their reusability.

The key aspect of this paradigm is **managing state from the outside**. Instead of storing component state internally, we delegate state management to higher-level components that utilize them.

Let's take a look at how we can achieve that.


## Managing state internally 

Imagine we're creating a **Dropdown component**. The typical approach that many developers would take is as follows: when a user selects a field from the dropdown, we set that value within the dropdown component itself.

This way, we can set the component's state from the inside.

![Managing state internally](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnm4kvup8slwbal90tpj.png)

However, while creating the dropdown component with its internal state may seem sufficient for most scenarios, let's consider a different use case.

Imagine we want to reuse the Dropdown component in a filter page within our application. In this scenario, instead of setting the selected value within the dropdown itself, we would set a filter tag just below the dropdown when a user selects a field.

**Now, our previous approach doesn't work**. Some people might consider one of these options:
- Create another new component just for this new use case.
- Create a prop that indicates the component how it should behave.

Notice that both these two alternatives break the [Open Closed Principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle): **any time we want our component to support one new use case, we'll have to modify it**. None of those are a desirable choice.


## Managing state with callbacks

The best approach here is to make our original component reusable by **uplifting its state**. But, how will we be able to set the component's state if we uplift it? Well, that's where **callbacks** come into play.

![Managing state from the outside](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y68jnfzon8jvq4sw2o4w.png)

Rather than having a complex component manage its own state depending on its use case, we lift the state up to the parent component and pass down the necessary data and callbacks as props.

This way now, our component is **opened for extension**, but **closed for modification**

The dropdown component doesn't know what the callback does. It can set the dropdown value, set some filters, etc. It can do whatever we want. 

The component just knows that it has to execute the callback. What the callback does is not its responsability. It's its parent's.


---


There are situations where we develop a component that we know we're not going to reuse. In such cases, applying this paradigm could potentially increase complexity. Therefore, it's important to use this approach wisely.

Instead of tightly coupling your components to specific use cases, consider **composing** them from the outside when necessary.

And that's why you should remember to **Keep it ~~Simple~~ Silly, Stupid**.