Why I prefer "connect" over "useSelector" using redux?
Tags: react, redux, javascript, frontend
Published: 2021-05-24 06:52:31

It's been almost two years since new hooks have arrived into `react-redux` and I've had enough chance to work on multiple long-running projects that uses both the old and new approaches to connect with Redux. Here is my conclusion for short: `connect` is better that `useSelector`. Here is why:

In version 7.1.1, `react-redux` introduced their hooks API and updated their website with a [tip](https://react-redux.js.org/api/hooks) that endorses hooks over the old `higher-order component` approach:

> We recommend using the React-Redux hooks API as the default approach in your React components.
The existing connect API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript.

![Toy Story scene with "Hooks, hooks everywhere" caption](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ik4apyv8wtpgmyyk0980.jpg)

React hooks made a great success since it's first introduction. It enables us to write tidy and understandable  logic blocks. Yet, it doesn't mean that it is a one-size-fits-all solution for every use-case.

## Ease of use
I must admit that hooks are easier to grasp and use than connected components. Using `connect` requires more boilerplate code. It also requires to know concepts like higher-order components, `bindActionCreators`, etc. to understand how it actually works. On the other hand, knowing how hooks work is enough to understand `useSelector` and `useDispatch` correctly. However ease of use is not always the most important think that we consider while choosing one approach over another.

Redux is really powerful when it comes to managing application state. But with great power comes great responsibility. We should give importance to how state is structured and be picky about what should be included into it and what is not. Only the data that is needed to be long-lived and globally available should make into Redux state. From this perspective, ease of use becomes our enemy. As React's `useState` hook and Redux's `useSelector` hook offer similar API surfaces, developers tend to put most of the state to their Redux state instead of picking only necessary ones. In the long run, it becomes bloated and structured by what components need rather than data itself.

Consider following example:
```javascript
const SomeComponent = () => {
  const dispatch = useDispatch();

  return (
    <div>
      {/* Component content goes here */}
      <button onClick={() => dispatch(openConfirmDialog())}>Click Me!</button>
    </div>
  );
};

const ConfirmDialog = () => {
  const isOpen = useSelector(state => state.foo.bar.isDialogOpen);

  return isOpen ? <div>{/* Dialog content goes here */}</div> : null;
};
```

In most cases, you don't have to put `isOpen` into your global application state. Avoiding prop drilling is not an excuse.

The problem here is not caused by `useSelector` itself. However it makes making mistakes easier. On the other hand, if we were using `connect` instead, we would think twice to put it into global state.

## Maintainability
As Software Developers, our primary job is maintenance of existing code, not writing new ones. As once Martin Fowler said,

> "Any fool can write code that a computer can understand. Good programmers write code that humans can understand."

{% twitter 1385573425360609281 %}

Before React's introduction of hooks, we used to use presentational components and container components to make sure that business logic is separate from UI code. Hooks have changed that approach. We can now put business logic into custom hooks and use them in multiple components. However, the same is not correct anymore for UI code. Hooks are directly wired into them and it is not possible to use them by connecting to different data sources.

`useSelector` is a good example of such cases. I've seen this in many codebases: Components and their sub-components were so tightly coupled into Redux state and therefore developers tended to copy their UI code and create another component instead of using the already available ones. However the solution is simple: Use `connect` to create a container component and let the presentational part independently available for future uses. It provides just a right amount of abstraction without much complexity.

## Loose coupling
Another problem caused by using `useSelector` arises while writing tests for your code. As the hooks are embedded directly into your component it is impossible to test them independent of the application state. Thus, even the simplest components are required to be connected to Redux.

`connect` prevents this from happening as well. You can always test your presentational component independently. This allows us to write unit tests specific to that component without connecting it to Redux populated with mock data.

## Conclusion
These differences might seem trivial at first glance. But it becomes more and more obvious as project grows. Therefore I suggest to use `connect` instead of `useSelector` on your projects as well. It will make things harder, yes, but sometimes in software development making something slightly harder is better to prevent immature decisions taken.