Separation of concerns with custom React hooks
Tags: react, javascript, webdev
Published: 2021-03-21 13:55:06

**React** is without a doubt one of the **most popular** front-end JavaScript frameworks / UI libraries around. However, it doesn't mean that it's the best or that everyone likes it.

Among some of the more **technical reasons** behind people disliking React is, surprisingly, one of its biggest features as well - **[JSX](https://facebook.github.io/jsx/)**. An extension to standard JavaScript that allows you to use **HTML-like syntax** in your React components.

How such a recognizable part of React, one that clearly stands to improve readability, and ease-of-writing one's code can be turned into a con? Well, it all comes down to the **separation of concerns**.

# Separation of concerns

Before we dive in, I'd like to explain exactly what separation of concerns is, not to leave out any nuances.

So, separation of concerns means having **clear lines** between **different concepts**/pieces of something. In programming, JSX is a clear example of ignoring this rule. No longer do we have a *"template"* describing component **structure** in a separate HTML file and its **logic** in a JS one, but both (or more if you're using CSS-in-JS) are mixed together to form what some consider *perfect harmony*, and others - *uncontrolled chaos*.

## Personal preference

Alright, so mixing the *"view"* and the *"logic"* together brings about the disruption of the separation of concerns. But is that really bad and does that mean that you always have to keep your component's view and logic separately?

No and no. First off, a lack of separation of concerns isn't necessarily a bad thing. It's a matter of **personal preference** of a developer or a team, and other guidelines. You don't have to keep your logic and view separately. But if you do, it still doesn't mean that each one of them needs a separate file. Perfect examples of that are [Vue Single File Components](https://vuejs.org/v2/guide/single-file-components.html#What-About-Separation-of-Concerns) (SFCs) or simply pure HTML file with `<script>` and `<style>` tags inside them.

# React hooks

Separation of concerns is one thing, and **React hooks** the other.

So, **[React hooks](https://reactjs.org/docs/hooks-intro.html)** have been around for quite a while now (almost 2 years since [stable release](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html)), so they are rather well-known and already *"covered to death"* by many other blogs and devs alike. But let's have a brief overview one more time.

React hooks allow developers to add **state** and use other special **React features**, inside **functional components**, as opposed to the prior requirement of class-based ones. There are 10 of them built-in (*v17.0.1*), each for handling different React features, from which only 4 are commonly-used (`useState()`, `useEffect()`, `useContext()`, and `useRef()`) and you can naturally **[create your own](https://reactjs.org/docs/hooks-custom.html)**. And it's this one last bit of information that we're most interested in.

# Custom hooks

While React hooks themselves should be somewhat well-known, the process of **creating a hook** of your own is a bit less likely.

You see, the built-in hooks are *"more than enough"* to built solid React components, and if not, there's almost certainly an open-source library of some kind in the immense **React ecosystem** that *"hookifies"* the exact functionality you seek. So, why bother with learning more about custom hooks if this isn't necessary?

## Creating a hook

That's a fair point. Custom hooks aren't necessary to do anything, but they can certainly make your life easier - especially if you like separation of concerns.

But everything will come in time. First - how to make a custom hook? Well, it couldn't be easier. A custom hook is just a **function** that uses **other hooks**. It's really that simple. It should also follow the ["rules of the hooks"](https://reactjs.org/docs/hooks-rules.html), which can be easily done if you're using **ESLint** and [proper official config](https://www.npmjs.com/package/eslint-plugin-react-hooks), but that's it.

To be honest, you don't even have to do any of those things - using other hooks is not required (but rather common), and if your code is of good quality, custom hook name starts with *use,* and you use hooks as intended (at the very top-level of React component), then you should be fine.

## Examples

Here's a very simple hook that runs the provided callback every second (because I couldn't think of anything better 🙃):
```javascript
const useTick = (callback) => {
  const handle = setInterval(() => {
    callback();
  }, 1000);

  return () => {
    clearInterval(handle);
  };
};
```
...and here's how you can use it:
```javascript
const Component = () => {
  const stopTick = useTick(() => {
    console.log("Tick");
  });

  return <button onClick={stopTick}>Stop ticking</button>;
};
```
As for a hook that depends on another hook, here's one that forces your component to update without noticeable state change by using `useState()` *"in the background"*.
```javascript
const useForceUpdate = () => {
  const [value, setValue] = useState(true);

  return () => {
    setValue(!value);
  };
};
```
...and here's a usage example:
```javascript
const Component = () => {
  const forceUpdate = useForceUpdate();

  return <button onClick={forceUpdate}>Update component</button>;
};
```
As a side-note, it's worth saying that such *force update* usually shouldn't be used. Most of the time it's either pointless or indicates some potential errors in your code. The only exception to this rule are uncontrolled components.

# Solution proposal

By now I think you see where this is going. No matter how pointless my examples were, both of them still share one advantage - they **abstract logic** away from the main component function, making it look cleaner as result.

Now, it's only a matter of scaling this idea up, potentially moving the resulting hook away from the component file itself, and voila! You've got yourself a pretty good separation of concerns - in React!

It might seem like a simple revelation, but I've only come to it a while ago, and using it in my React project since then I must admit - it's a pretty nice solution.

You might agree with me on this idea or not (leave your comments down below), but it doesn't really matter. I'm just presenting a potential strategy to arrange your code that I find pretty nice, in hopes that it'll help you as well.

## Best practices

So, if you end up at least trying out such an approach in one of your projects, then I do have some *"best practices"* that I personally follow and that might be of interest to you:

-   only apply this tactic if your component's logic takes **\>10 lines** or has a lot of smaller hook calls;
-   put your hook in a separate file, which ideally should have **no JSX** in it (`.js` vs `.jsx` files);
-   keep your **naming consistent** - e.g. hook in `logic.js` or `hook.js` (with appropriate hook naming as well, e.g. `useComponentNameLogic()`) and the component itself in `view.jsx` or `index.jsx` under a single folder, with optional `index.js` file (if it isn't reserved for the component already) for re-exporting the necessary bits;
-   keep only the simplest callbacks and event listeners in the JSX file, and move the rest to the hook;
-   if using **CSS-in-JS library** that deals with hooks (e.g. `useStyles()`) then place it in a separate file, or at the top of the component file if it's not too big;
-   remember to **organize your hook's code** correctly - separate some of it to outer functions, and maybe even smaller hooks, if the logic is reused across different components.

# What do you think?

That's my proposal for implementing separation of concerns in React. Is this the best approach that you must use? Definitely not, besides there's no *"best approach"* at all. Again, I just discovered that this one fits my needs, and I wanted to share it with you in hopes that it might help you as well.

So, what are your thoughts on such an approach? Would you like to see more posts where I share some personal **code style tips** in the future? If so, let me know in the **comment section** below.

As always, for more content like this, be sure to follow me on [Twitter](https://twitter.com/areknawo), [Facebook](https://facebook.com/areknawoblog), or through [my newsletter](https://areknawo.com#newsletter). Thanks for reading and happy coding!

> This post was written with ease, made grammatically-correct, and cross-posted here within 1 click thanks to **[CodeWrite](https://codewrite.io/)** with its great editor, smooth Grammarly integration, and "one-click publishing". Try it for free, and use the code `first100` to get **20% off** your subscription (only **$2.40/month**!)