DEV Community

Cover image for Replacing redux HOCs with hooks
Antonio Erdeljac
Antonio Erdeljac

Posted on • Edited on

Replacing redux HOCs with hooks

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

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);
Enter fullscreen mode Exit fullscreen mode

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

import { getUsers, resetUsers } from 'actions/users';
import { selectUsers } from 'store/users';
Enter fullscreen mode Exit fullscreen mode

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.

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

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

  ...
}
Enter fullscreen mode Exit fullscreen mode

3. PropTypes

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

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

4. connect HOC

In this part of the code, we are utilizing mapStateToProps and mapDispatchToProps through connect high order component.

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

export default connect(mapStateToProps, mapDispatchToProps)(App);
Enter fullscreen mode Exit fullscreen mode

Using react-redux hooks

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

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;
Enter fullscreen mode Exit fullscreen mode

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:

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 }
}
Enter fullscreen mode Exit fullscreen mode
import { useAppStore } from './hooks';

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

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

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

  ...
}
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (2)

Collapse
 
alvpopa profile image
Valentin A. Popa

You forgot to return actions from the useAppStore hook. Nice article!

Collapse
 
antonioerdeljac profile image
Antonio Erdeljac

Thanks, Valentin! It's updated.