Replacing redux HOCs with hooks
Tags: redux, react, javascript
Published: 2020-11-26 00:50:23

You're probably familiar with the concept of using redux HOC called `connect`. It probably looks something like this (abbreviation):

```javascript
import { getUsers, resetUsers } from 'actions/users';
import { selectUsers } from 'store/users';

const App = ({ users, getUsers, resetUsers }) => {
  useEffect(() => {
    getUsers();

    return () => resetUsers();
  }, [getUsers])

  ...
}

App.propTypes = {
  users: PropTypes.arrayOf(PropTypes.object),
  getUsers: PropTypes.func.isRequired,
  resetUsers: PropTypes.func.isRequired,
};

const mapStateToProps = { users: selectUsers() };
const mapDispatchToProps = { getUsers, resetUsers };

export default connect(mapStateToProps, mapDispatchToProps)(App);
```

A simple component which uses redux's `connect` HOC to provide `<App />` component with `getUsers`, `resetUsers` and `users` prop. 

**Let's see how hooks can simplify our code.**

Analyzing the code:

### **1. Imports**
In this part of the code, we are importing our actions and selectors used in `mapStateToProps` & `mapDispatchToProps`

```javascript
import { getUsers, resetUsers } from 'actions/users';
import { selectUsers } from 'store/users';
```

### **2. Component itself**
In this part of the code, we are defining our `App` component and destructuring `users`, `getUsers` & `resetUsers` from the prop. We utilize a simple `useEffect` hook to call users on mount, and reset them on unmount.

```javascript
const App = ({ users, getUsers, resetUsers }) => {
  useEffect(() => {
    getUsers();

    return () => resetUsers();
  }, [getUsers])

  ...
}
```

### **3. PropTypes**
In this part of the code, we are defining prop types used by our component.

```javascript
App.propTypes = {
  users: PropTypes.arrayOf(PropTypes.object),
  getUsers: PropTypes.func.isRequired,
  resetUsers: PropTypes.func.isRequired,
};
```

### **4. connect HOC**
In this part of the code, we are utilizing `mapStateToProps` and `mapDispatchToProps` through `connect` high order component.

```javascript
const mapStateToProps = { users: selectUsers() };
const mapDispatchToProps = { getUsers, resetUsers };

export default connect(mapStateToProps, mapDispatchToProps)(App);
```

# **Using react-redux hooks**

If we were to use hooks instead of HOCs, we'd end up with something like this:

```javascript
import { useSelector, shallowEqual, useDispatch } from 'react-redux';

import { getUsers, resetUsers } from 'actions/users';
import { selectUsers } from 'store/users';

const App = () => {
  const dispatch = useDispatch();
  const users = useSelector(selectUsers(), shallowEqual)

  useEffect(() => {
    dispatch(getUsers());

    return () => dispatch(resetUsers());
  }, [getUsers, dispatch])

  ...
}

export default App;
```

Notice how code is much cleaner, tidy, and implementation is done with less code?

Using react-redux hooks we've eliminated the need for `mapDispatchToProps` & `mapStateToProps` constants, as well as HOCs wrapping of our component.

Further implementation could be implementing custom hooks to handle redux logic, and would be used something like this:

```javascript
import { useSelector, shallowEqual, useDispatch } from 'react-redux';

import { getUsers, resetUsers } from 'actions/users';
import { selectUsers } from 'store/users';

export const useAppStore = () => {
  const dispatch = useDispatch();
  const users = useSelector(selectUsers(), shallowEqual);

  const actions = useMemo(() => ({
    getUsers: dispatch(getUsers()),
    resetUsers: dispatch(resetUsers()),
  }), [dispatch]);

  return { users, actions }
}
```

```javascript
import { useAppStore } from './hooks';

const App = () => {
  const { users, actions } = useAppStore();

  useEffect(() => {
    actions.getUsers()

    return () => actions.resetUsers()
  }, [actions.getUsers, actions.resetUsers])

  ...
}
```

With this, we've achieved separation of concerns.

### **Conclusion**
React hooks offer many new ways to solve old problems - one of them being selectors and action dispatches of redux. Most of the libraries which HOCs you're using are providing hooks as well. Make sure to update your packages and check the documentation for the hooks implementation tutorial to keep your codebase fresh!