⚛️ Organizing Code in a React Component
Tags: webdev, react, typescript, javascript
Published: 2024-04-07 07:23:58

Organizing code in a React component is often overlooked sometimes, but things can get complex when dealing with Higher-Order Components (HoCs), `forwardRef`, and `memo`. It can lead to cluttered and hard-to-maintain code if not handled properly. This article aims to address these issues by proposing a more manageable way to structure your code and improve your productivity.

## 1️⃣ Managing HoCs, `forwardRef`, and `memo` in a React Component

### Problem Statement

As a React developer, I used to struggle often with organizing my components, especially when incorporating `memo` and `forwardRef`. The example below, taken from the [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forward_and_create_ref), demonstrates this challenge:

```tsx
import { forwardRef } from 'react';

interface FancyButtonProps {
  type: 'submit' | 'button';
  children?: React.ReactNode;
}

export const FancyButton = forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
  <button ref={ref} className="MyClassName" type={props.type}>
    {props.children}
  </button>
));
```

From my own experience, this code presents several problems:

- The code appears cluttered compared to a "bare" component due to the wrapping of the component within `forwardRef`.
- Types are not really in the optimal places. The generics of `forwardRef` have a reversed order compared to the actual parameters used in the component: `<HTMLButtonElement, FancyButtonProps>` vs `(props, ref)`.
- Refactoring becomes cumbersome, as it requires careful attention to brackets and parentheses. Say you no longer need `forwardRef`. Even with the help of something like Rainbow Brackets, dealing with those brackets and parentheses can be frustrating sometimes, especially when the component is large.
- What if you want to add `memo` or some kinds of custom HoCs to the component, and some states or functions inside it? It'll become even more of a mess:

```tsx
import { forwardRef, memo } from 'react';

import { useStyles } from '@/modules/core/styles';

interface FancyButtonProps {
  type: 'submit' | 'button';
  children?: React.ReactNode;
}

export const FancyButton = memo(
  forwardRef<HTMLButtonElement, FancyButtonProps>(({ type, children }, ref) => {
    const classes = useStyles();

    return <button ref={ref} className={classes.button} type={props.type}>
      {children}
    </button>
  })
);
```

### Proposed Solution

After getting fed up with all the trouble when organizing my component code that way, I eventually came up with a way to tackle those issues. Consider the following approach:

```tsx
import { forwardRef, memo } from 'react';

import { useStyles } from '@/modules/core/styles';

interface FancyButtonProps {
  type: 'submit' | 'button';
  children?: React.ReactNode;
}

const FancyButtonBase = (
  { type, children }: FancyButtonProps,
  ref: React.ForwardedRef<HTMLButtonElement>
) => {
  const classes = useStyles();

  return (
    <button ref={ref} className={classes.button} type={type}>
      {children}
    </button>
  );
};

export const FancyButton = memo(forwardRef(FancyButtonBase));
```

The code is self-explanatory. The actual code of the component lives in a function component whose name has a `Base` suffix to it. Then we export the component below, with all the HoCs, `memo`, and `forwardRef`.

This solution offers several benefits:

- The actual component code is separated from the HoCs, `memo`, and `forwardRef`, making it resemble a "bare" component.
- Types are where they should be: `(props: FancyButtonProps, ref: React.ForwardedRef<HTMLButtonElement>`.
- Should you need to refactor this code, as in you no longer use `ref`, you simply have to remove the second parameter and `forwardRef` without having to deal with brackets and parentheses.
- If nested HoCs are required, adding or modifying them is straightforward and the code still remains readable:

```tsx
import { forwardRef, memo } from 'react';

import { useStyles } from '@/modules/core/styles';
import { withWhatever } from '@/modules/core/hocs';

interface FancyButtonProps {
  type: 'submit' | 'button';
  children?: React.ReactNode;
}

const FancyButtonBase = (
  { type, children }: FancyButtonProps,
  ref: React.ForwardedRef<HTMLButtonElement>
) => {
  const classes = useStyles();

  return (
    <button ref={ref} className={classes.button} type={type}>
      {children}
    </button>
  );
};

export const FancyButton = memo(forwardRef(withWhatever(FancyButtonBase)));
```

This approach adds a single line of code to your component but significantly improves readability and maintainability. Even without using any HoCs, `memo`, or `forwardRef`, I still do this for "bare" components: `export const FancyButton = FancyButtonBase`.

We can take this a step further and try to improve our productivity with a very useful but not well-known VSCode extension.

## 2️⃣ Improving Productivity with the "Folder Templates" Extension

The GIF below demonstrates the power of [the "Folder Templates" extension in VSCode](https://marketplace.visualstudio.com/items?itemName=Huuums.vscode-fast-folder-structure) (the GIF might take a bit long to load):

![Folder Templates Extension Demo](https://res.cloudinary.com/dip6bddoz/image/upload/v1712480236/react-folder-templates-minest_e1qg9z.gif)

You only have to enter the name of the component, and voila!

Basically, you can also tell AI to write this boilerplate code for you, but I find using this extension much quicker, and it's highly customizable.

If you need me to share my pre-defined React-specific folder template settings, please let me know in the comments.

## 🏁 Conclusion

Organizing code in a React component, especially when using `memo`, `forwardRef`, and HoCs, can be a daunting task. However, by separating the actual component code from the HoCs and ensuring proper type declarations, you can create cleaner, more maintainable code. Additionally, using tools like the "Folder Templates" extension in VSCode can help streamline your development process and boost productivity.

In case you think it was a good read, you'll probably find my previous post useful as well:

{% link https://dev.to/itswillt/folder-structures-in-react-projects-3dp8 %}

---

If you're interested in Frontend Development and Web Development in general, follow me and check out my articles in the profile below.

{% user itswillt %}