Clean Code in React
Tags: react, frontend, cleancode, webdev
Published: 2024-07-03 13:47:38

Hello everyone, I'm Juan, and today I want to share with you some tips and tricks that I use to write more reusable code. For the past 2 weeks, I've been writing about how to develop projects faster and how it's irrelevant to spend too much time looking for the perfect code at the outset of the project. Although, you are not always going to be working on your own projects, and sometimes you won't be in a rush. Or maybe, just maybe, you are one of those accountable developers who, after spending time creating something amazing in just [48 hours](https://dev.to/juanemilio31323/48hs-is-all-you-need-39fa) and applying the [strategies](https://dev.to/juanemilio31323/how-i-build-projects-faster-my-stack-and-strategies-3hpg) that I shared, now you are at the point where you have to fix the mess that you've created, developing as fast as you could.

The example project that I'm going to use is React, but you can apply most of these things practically anywhere you want. I'm going to be showing folder structures, mentioning the architecture that I'm following, and also providing code snippets with explanations and examples of multiple cases.

## What is going on with the industry?
---
I've been lucky, and thanks to that I've worked at companies of different sizes and styles, some bigger, some smaller, but in all of them, I saw a pattern that repeats everywhere: the code is broken. No structure whatsoever—logic, styles, types, everything in the same place. That might not be a problem when you just have a bunch of files, but when your codebase is gigantic, it is really easy to make it impossible to grow or sustain over time.

Right now, I'm working for a huge company with over 29,000 employees. You wouldn't expect a company like this to make the mistakes that I was describing, but it does. After talking to people who theoretically know how to lead a project and help sustain a readable and scalable codebase, I came to the conclusion that most of us lack the knowledge or interest, or both, when it comes to structuring the code. Hopefully, this post will help someone out there write better code and know how to sustain a project over time.

## The architecture that I use - let's scream
----
Hopefully, you've heard about this architecture before. It's called _Screaming Architecture_, and the name is no joke—it literally screams at you. When you enter the project, it perfectly summarizes what's going on without needing you to run the project. Let me show you:

![Basic folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcfyw8ifnjcj0e7yy72t.png)

It's worth mentioning that I made some modifications to the _Screaming Architecture_ to better suit my needs, and that is something you can do too. As always, there is no perfect solution, just solutions that may adapt better to your specific case. Feel free to keep the things that work best for you and discard the rest. But when you do it, be honest with yourself and ask the following question: "Am I really doing this because it is better or just because I don't want to learn something new?"

### Explaining the basic structure:

In the _components_ folder, you'll create all the components that you need to reuse across your application. These are not specific components, and if you are going to put it there, it is because you are already using that component and you want to reuse it somewhere else.

In the _interfaces_ folder, you'll define all your types. We are doing it this way because most of the time, you are sharing types across your entire application, so it doesn't make much sense to me to have the types in a deeper folder.

![Basic folder structure interfaces](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kc1yq7n4r3yfjlr3nol.png)

Finally, in the _features_ folder, you'll have most of the code, following a recursive structure:

![Components structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/beze20ur6qyo9hjco7fc.png)

As you can probably see here, we are creating a _Logic_ file because we don't want the logic of our application leaking into our visual components. Let me show you an example in _React_ to see how this works. The component that I'm going to show you is _Window_. It renders on the screen the Window's width of our user. You'll notice that we have almost no logic here, just a `<p>` tag that is returning the _width size_ of the screen.

```tsx
import Logic from "./Logic";

const Window = () => {
  const { size } = Logic();
  return <p>{size}</p>;
};

export default Window;

```

And here's the logic:

```typescript
import { useState, useEffect } from "react";
const Logic = () => {
  const [size, setWindowSize] = useState(0);

  useEffect(() => {
    // get the windows width
    setWindowSize(window.screen.width);
  }, []);

  return { size };
};

export default Logic;
```

We have successfully isolated our logic and our view. There will be people reading this and thinking that this is similar in some ways to the [Model View Controller](https://developer.mozilla.org/es/docs/Glossary/MVC) pattern, and they are correct. This is really helpful and most of the time will avoid having a file that is overwhelmingly huge to read. But this is not a silver bullet, and there will be cases where you'll have to take other approaches. So let's see other concepts and examples.

## Abstraction and Encapsulation

When I started programming, I remember that one of the things that I hated the most was _OOP (Object-Oriented Programming)_. For some reason, I couldn't get it. Most of the time, I found myself asking why I would ever write something like that. At some point in my life, I realized that _OOP_ was amazing and really helpful. Concepts like _SOLID_ or _Abstraction_ were pillars of any _clean code_. So for that reason, before moving to some code snippets, I consider it appropriate to make a stop on some of those concepts.

### Abstraction

It is by far one of the most important things on the priority list when it comes to writing the best code possible, and also most of the time, it's one of the most forgotten. I've seen people who write code that astonishingly solves the problem they are presented with, but when you start to take a deeper look and ask yourself (or them) how this is going to be reusable, you find no answer. Most of the time, that is due to a lack of understanding of the _Abstraction_ principle.

Abstraction can be understood as the capacity to ignore the obvious and put the necessary attention on the more general aspects of the things that we are confronting (the big picture). If you are trying to describe a glass of water, you may say that: _"it is a piece of transparent material, containing water,"_ and indeed, that would be correct... on the small picture, but useless on the big picture. Instead, we can say: _"it is a piece of material, with some geometry, restrained to a structure able to contain liquids, with a color and transparency determined."_ The second description is able to generalize a lot better than the first one, giving us the opportunity to use the same description for many things. This is _Abstraction_, the skill to see the "big picture." Work on it, write code thinking about it, and you from the future and the people who will have to work with you will be grateful.

Do you see any _Abstraction_ in the previous example? It has, but it might be hard to see in its current state. Let me make a little change and see if you get it:

```tsx
import { useState, useEffect } from "react";
const useWindowSize = () => {
  const [size, setWindowSize] = useState(0);

  useEffect(() => {
    // get the windows width
    setWindowSize(window.screen.width);
  }, []);

  return { size };
};

export default useWindowSize;
```

Now instead of "Logic," we have _useWindowSize_. Separating the logic from the view gives us the opportunity to see that we have a piece of code that is reusable. Now that we have this custom hook that we can reuse and generalize a lot better, what do you think if we move it to the _utils/_ folder, so we can reuse it later?

### Encapsulation

Would you give anyone entire access to your phone? Most likely you said no; otherwise, you are crazy since with that, any person would be able to enter your bank account and personal contacts list. We don't want that to happen, so we'll let **some** people **access** some part of our phone. We won't expose our entire phone to everybody. This, my dear friend, in an intricate and funny way, is _Encapsulation_. You could summarize it as: _"Some can see and touch it; some just can see it."_

Great, this is helpful in many ways for your code. It becomes handy, especially when you are working with too many people or when you have code that is going to be used by someone else, like in the case of my [React Library](https://www.npmjs.com/package/smart-layout).

Now we understand what _Encapsulation_ is. Do you see it applied in any way in our _useWindowSize_? Yes! You got it. We are keeping _setWindowSize_ private, just making it accessible to the code inside of _useWindowSize_ and no one else. That's great because in that way, no one will be able to alter the window size besides the logic of our code, making it more secure and predictable.

## Finally - Code Snippets

Sorry for the stop on _OOP_ concepts, but it's necessary. It's amazing how those two concepts can change your life. With the new knowledge and understanding that we now have, we'll be able to better appreciate the code that we are going to see.

### I haven't seen it anywhere else

The code that I'm going to show you is something that I've been using maybe too much lately and for some reason, no one is talking about it. I'll give you context. Have you ever found yourself using a perfect and reusable component, but each time you have to reimplement some specific logic because you need to access that from a higher component? No? Maybe just me... Anyway, let's see the solution.

```tsx
type fields = "text" | "image" | "number"
interface ModalProps {
	show: boolean;
	fields: fields[]
}

const Modal = ({ show, fields }: ModalProps) => (
	return show ? <div className="modal">
		{fields.map((field) => {
			// Modal code...
		}}
	</div> : ''
)

const ImageGallery = () => {
	const [show, setShow] = useState(false)
	const images = [...]
	return (
		<>
			<Modal show={show} fields={["image", "text"]}/>
			{images.map((image, i) => {
				<img src={image} onClick={() => setShow(true)}/>
			})}
		</>
	)
}
```

Perfect, we have an _ImageGallery_ that is using our "beautiful" _Modal_. In this case, imagine that the modal is dynamically creating a form to upload an image with a description. Now let's say that I want to add another page similar to _ImageGallery_, maybe a _Comments_ section. I'll have to re-write the _show_ logic. Let's try to avoid it:

```tsx
type fields = "text" | "image" | "number"
interface ModalProps {
	fields: fields[]
}

const ModalHandler = () => (
	const [show, setShow] = useState(false)
	const Modal = ({ fields }: ModalProps) => (
		show ? <div className="modal">
			{fields.map((field) => {
				// Modal code...
			}}
		</div> : '')
	return { Modal, show, setShow }
)

const ImageGallery = () => {
	const { show, setShow, Modal } = ModalHandler()
	const images = [...]
	return (
		<>
			<Modal fields={["image", "text"]}/>
			{images.map((image) => {
				<img src={image} onClick={() => setShow(true)}/>
			})}
		</>
	)
}

const Comments = () => {
	const { show, setShow, Modal } = ModalHandler()
	const comments = [...]
	return (
		<>
			<Modal fields={["text"]}/>
			{comments.map((comment) => {
				<p onClick={() => setShow(true)}>
					{comment}	
				</p>
			})}
		</>
	)
}
```

We did it! In this case, it is an overkill scenario because it is just a show and _setShow_ that may be arguably re-implemented in every case, but the important thing is the concept. With this approach, we can create more reusable components, and at least for me, it is more readable than the _composition pattern_. Speaking of which, why don't we take a look:

### Composition Pattern 

Let's create a grid to preview images:

```tsx
const ImageGrid = ({ images }) => {
	const handleAnimations = useCallback(() => {
		...
	}, [])

	useEffect(() => {
		handleAnimations()
	}, [])

	const complexGridLogic = () => {
		...
	}
		
	return (
		<div className="magic-grid">
			{complexGridLogic()}
			{images.map((image, i) => {
				<div className="animated-container" id={`animate-${i}`}>
					<img src={image}/>
				</div>
			})}
		</div>
	) 
}
```

Great, we have our ImageGrid (again, it is just a concept). It will mount images and then animate them. Also, it has a _"complexGridLogic"_. Now let's say that I want a _CommentsGrid_ with extremely similar behavior. What a problem. Let's see how the _Composition Pattern_ can save us:

```tsx
const AnimatedContainer = ({ children, id }) => {
	const handleAnimations = useCallback(() => {
		...
	}, [])

	useEffect(() => {
		handleAnimations()
		...
	}, [])

	return <div className="animated-container" id={id}>{children}</div>
}

const MagicGrid = ({ children }) => {
	const complexGridLogic = () => {
		...
	}
	return (
		<div className="magic-grid">
			{complexGridLogic()}
			{children}
		</div>
	)	
}

const ImageGallery = ({ images }) => {
	return (
		<MagicGrid>
			{images.map((image) => (
				<AnimatedContainer id={image}>
					<img src={image}/>
				</AnimatedContainer>
			))}
		</MagicGrid>
	)
}

const CommentSection = ({ comments }) => {
	return (
		<MagicGrid>
			{comments.map((comment) => (
				<AnimatedContainer id={comment}>
					<p>{comment}</p>	
				</AnimatedContainer>
			))}
		</MagicGrid>
	)
}
```

I see it and I love it. What a wonderful world it would be if everyone cared as much as you and I do about our code. Now we have 2 reusable components and 2 implementations that are perfectly reusable. This also gave us something called:

## Separation of concerns 

At the beginning of this post, I showed you the structure that I like to use for my projects. I think it is understandable and cleaner than many things out there, and a big part of that is thanks to the _Separation of Concerns_, a principle that I always try to follow. You can summarize it as: _don't take responsibility for someone else's actions_. It's that easy. The _button_ shouldn't have the logic of the _input_, obviously, and the _Grid_ shouldn't be in charge of rendering your images, but instead rendering any children.

It's that easy, really, and for some reason, sometimes I find myself arguing about it with some random co-worker (this happened to me last week).

## Wrapping up

I'm finishing this post, and I feel like there's something off with it, but I'm not sure what it is. I have the feeling that I've tried to cover so many aspects that I couldn't go much deeper on any of them. So if you are interested in me talking more in-depth about some of these aspects, let me know.

## Before you go

I'm thinking of posting on [X](https://x.com/Juan31323). Would you follow me? Thank you in advance, and if you really enjoyed the post, would you help me pay my rent?

[---------------------------------------------------------------------------] 0% of $400

<a href="https://www.buymeacoffee.com/juanemilio" rel='noopener' target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 250px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>