by Francesco Agnoletto

React hooks vs Redux

Less is more

Photo by Fabien Bazanegue on Unsplash

React is by far the most popular JavaScript framework, its learning curve is pretty linear, it has a rich and growing environment around it and a team behind it dedicated to improving it more and more every day.

Managing state in React has always been a topic full of discussions behind it, Redux was king for a good chunk of time, then other libraries started coming out doing a similar thing but better in one or more aspects.

Example Redux project vs basic React hooks project

Let’s go over to how to create a simple app that increments or decrements a counter with 2 buttons.

Redux

Let’s assume Redux is already configured and working. For an example project, you can check out simple-redux-app.

npx simple-redux-app test-folder

(npx makes it so that you don’t have to install the package globally before using it if you have npm ≥ 5.2.0 this is available by default.) Once this is out of the way it’s time to write our logic. I usually prefer to define the action types in their own file for cleanliness.

// actions/types.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';

For the reducer, we want to be able to perform 2 actions, INCREMENT and DECREMENT that will modify our value by either plus or minus 1.

// reducers/counterReducer.js
import * as actions from '../actions/types';
function counterReducer(state = 0, action) {
  switch (action.type) {
    case actions.INCREMENT:
      return state + 1;
    case actions.DECREMENT:
      return state - 1;
    default:
      return state;
  }
}

Then, we have to define those actions.

// actions/counterActions.js
import { INCREMENT, DECREMENT } from './types';
export function addToCounter() {
  return {
    type: INCREMENT,
  };
}
export function removeFromCounter() {
  return {
    type: DECREMENT,
  };
}

Combining our reducer with other possible reducers should look something like this.

// reducers/index.js
import { otherReducer, combineReducers } from 'redux';
import counterReducer from './counterReducer';
export default combineReducers(
  { otherReducer, counterReducer }
);

And this is pretty much it, doesn’t look too complicated. Now to link it with our actual component.

import React from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
const Home = (
  { counterValue, handleIncreaseValue, handleDecreaseValue }
) => (
  <div>
    <h2>Home Page</h2>
    <p>The counter value is {counterValue}</p>
    <button onClick={handleIncreaseValue}>
      Add
    </button>
    <button onClick={handleDecreaseValue}>
      Remove
    </button>
  </div>
);
const mapStateToProps = state => ({
  counterValue: state.counterReducer,
});
const mapDispatchToProps = dispatch => ({
  handleIncreaseValue: () => {
    dispatch(actions.addToCounter());
  },
  handleDecreaseValue: () => {
    dispatch(actions.removeFromCounter());
  },
});
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home)

It seems like a lot of code for just a simple 2 button app that updates a value, in addition, we don’t share this component or actions with any other part of the app. All the files and logic we need to make this simple functionality overburden our application, a lot of complexity but we don’t gain much from it.

React Hooks

This is how the code would look like using locally scoped hooks.

import React from 'react';
const Home = () => {
  const [counterValue, setCounterValue] = React.useState(0);

  return (
    <div>
      <h2>Home Page</h2>
      <p>The counter value is {counterValue}</p>
      <button
        onClick={() => setCounterValue(counterValue++)}
      >
        Add
      </button>
      <button
        onClick={() => setCounterValue(counterValue--)}
      >
        Remove
      </button>
    </div>
  )
}
export default Home;

This is considerably less code, with the same performance if not better (Redux adds one more layer in the structure of the components), and only affects one file.

The logic is all in the same place, there’s nothing to investigate, on first look it’s obvious what the purpose of the code is. To know more about what the hooks API has to offer, you can check the official React docs here.

This code does not need any of the advanced features offered by Redux, we don’t need to travel forward or backward in the state history for a single action, we don’t need the development tooling or the rich console messages.

To know more about what Redux does and does not do, you can read a more complete article from its author here: You might not need Redux.

Hooks in React have much to offer, it’s a simple yet powerful tool.

You don’t need fancy tooling for most simple cases, leveraging React APIs can provide more benefits and less code complexity than a new library.

Simplicity is the ultimate sophistication.