React Hooks vs Redux: A Comparison

Posted on by Juan Machado
Reading Time: 7 minutes

Since incorporating Hooks into React, developers have had a popular debate. They argue whether Hooks can be used to do what can already be done with Redux or if Hooks can replace the use of Redux entirely to handle the state management of a React app. Before comparing React Hooks vs Redux, it is important to clarify some concepts related to them to demystify how state management is conducted in a React App. 

Hooks are functions that allow you to use different React features in your components without writing a component class. In most programming projects, you may need to use variables to represent data that changes. These variables can be structured in a javascript object that holds information in properties.

Let’s take, for example, a user profile feature where you’ll store relevant personal information about the user such as first name, last name, and user role. This data will change each time a different user is being managed. Each field will be represented in the component layout to be displayed to the user that can control other users in the app. The information will change on user interaction.

That’s where state comes into play. When a value in the properties is changed, React knows it needs to update the views of components that are connected to this state.

This article compares state management in React Hooks vs Redux.

What is React Hooks?

Introduced on ReactJS version 16.8, Hooks are functions that allow you to use some features of React, like state, without writing a class. This feature favors a functional approach when working with React, creating components, etc. Though rumored to do so in the community, classes are not being replaced in React. Rather, Hooks can work more efficiently with the same React concepts, allowing users to access props, state, context, refs, and lifecycle with a functional approach.

It is not required to refactor class components into functional ones. Class components remain working the way they have been previously as classes continue to be a part of React.

Hooks are a more direct way to work with the React concepts. Moreover, Hooks are created with performance in mind by avoiding the creation of unnecessarily complex classes for specific tasks like state management.

What is Redux?

Redux is a JavaScript library that introduces a global store to hold the state of variables across your app in a centralized place. The stores allow you to access state from almost any part of your project, no matter how complex the component hierarchy is.

It is important to note that even though the state is accessed globally, not every component can access it freely. There is a set of procedures established by Redux that need to be followed for a component to access the state, retrieve the current state, change it to a new state, etc.

State Management with Class Components

To do state management in a React app before incorporating Hooks, you were required to create a class component and declare the state in the class constructor.

class User extends React.Component{
     constructor(props) {
          super(props);
          this.state = {
               first_name: “Pedro”,
               last_name: “Perez”,
               user_role: “administrator”
          };
      }

updateUserRole = () => {
     this.setState({user_role: “editor”});
}

render() {
     return {
          <div>
               <p> First Name: {user.first_name} </p>
               <p> User Role: {user.user_role} </p>

               <button type=”button” onClick={this.updateUserRole}> Change Role to Editor </button>
          </div>
     };
}
}

ReactDOM.render(<User />, document.getElementById(‘userDisplay’));

This was good while you used the state only within the same component. But what if you needed to retrieve the state information in other components?

Let’s say you wanted to populate the user’s personal information (first name and last name) in a contact form inside your app to avoid the users having to type their information again. Your app’s component hierarchy starts to grow beyond the point of a simple structure. You need to pass the state between components as props (also known as props drilling). This is just not sustainable in the long run, and maintaining your app will become a difficult process.

React Hooks vs Redux State Management

State Management with React Hooks

React Hooks can be used to create a state locally in a component. Following the example of the user profile feature, the state could be defined this way.

const [user, setUser] = useState({
first_name: “Pedro”, 
last_name: “Perez”, 
user_role: “administrator”
});

In this example, user is the state and setUser is the function to update the state.

Then you can modify the state by implementing setUser with a new value for any of the fields in the object as follows.

const updateUserRole = () => {
     setUser(previousState => {
               return { ...previousState, user_role: “editor” }
          });
}

This will change the user_role property value to a different value from the original one in the state definition. Each time the state is updated, React will update the component fetching the state information to display the corresponding value properly. It is wrapped up in a function which can later be called from an event.

In this example, we will use it in an onclick event in a button element.

return(
     <>
          <p> First Name: {user.first_name} </p>
          <p> User Role: {user.user_role} </p>

          <button type=”button” onClick={updateUserRole}> Change Role to Editor </button>
     </>
)

That’s a much cleaner approach, and it opens the possibility of creating the state without needing to create a class component as before.

But there is still the props drilling issue. Hooks' state management approach works well for a small app with a minimal component structure. 

There is another approach to managing state with Hooks by implementing the useReducer hook. When the useReducer hook is implemented, it gives a more Redux-like feel. In principle, it uses an action and a reducer to change the state.

It’s important to note that this hook is defined in the React documentation as an alternative to useState. The useReducer hook can be convenient to implement in a larger app that involves changing several sub-values in the state. It can help keep the code organized for a complex structure.

First, useReducer accepts two arguments: a reducer function and the state. Then, it returns two items: the current state and a dispatch function.

Taking the same example as before, here it is written with React Hooks.

const theState = {
		first_name: “Pedro”,
		last_name: “Gonzalez”,
		user_role: “administrator”
	};

function myReducer(theState, theAction){
		switch(theAction.type) {
			case ‘changeRoleToEditor’:
				return{user_role: ‘editor’};
			case ‘changeRoleToAuthor’:
				return {user_role: ‘author’};
			default:
				throw new Error();
		}
}

function changeUserRole(){
	const [theState, dispatch] = useReducer(myReducer, theState);
		return(
			<>
				<div>
					<p> First Name: {theState.first_name} </p>
					<p> Last Name: {theState.last_name} </p>
					<p> User Role: {theState.user_role} </p>
					<button onClick={() => dispatch({type: 'changeRoleToEditor'})}>Change User Role to Editor</button>
<button onClick={() => dispatch({type: 'changeRoleToAuthor'})}>Change User Role to Author</button>
				</div>
			</>
	);
}

State Management with Redux

It is best to clearly understand what is happening when Redux is implemented in a React project. Redux has three main building pieces: the store, actions, and reducers. These are required to be connected, as they depend on each other.

In principle, actions allow sending information to the store, either retrieving the existing state to be displayed or changing the store. The store holds the state for the components to access globally, and reducers implement the logic that will execute depending on the action being sent to the store.

Store

A store is a JavaScript object. The store holds the app state globally without depending on the component hierarchy. This means any component connected to the store can access the state information and either display it or change it. 

Even though the store is a global entity, it doesn’t mean that all components can see it or interact with it. You must define which components will be connected to the store and enable interactivity.

import { createStore } from ‘redux’;
const userStore = createStore(rootReducer);
const userProfile = {first_nane: ‘Pedro’, last_name: ‘Perez’, user_role: ‘administrator’};
userStore.dispatch(updateUserRole());

A component can get the state from the store without knowing which other component declared that state or updated it. Then, a third component can update the state based on user interaction with your app. The state is updated in the store. All components listening to the state are updated per the newly-updated state.

Actions

Actions are events created with functions that return other actions called action creators. Actions send data to the store based on user interaction, internal events such as API calls, or form submissions. Actions are the only elements that can communicate directly with the store to retrieve information or update the state.

Mid-process, reducers listen to actions and execute a specific logic depending on the action type. Reducers hold the logic that will be performed based on the action (the information) being sent to the store.

export const changeUserRoleToEditor = () => (
{
     type: CHANGE_USER_ROLE_TO_EDITOR
}
)
export const changeUserRoleToAuthor = () => (
{
     type: CHANGE_USER_ROLE_TO_AUTHOR
}
)

Reducers

Reducers are functions that take the current state and action as arguments and return the updated state. Based on the action type, you can establish what logic the reducer will execute with a switch statement.

export default function myReducer ( state = initialState, action ) {
     switch(action) {
          case CHANGE_USER_ROLE_TO_EDITOR:
               return { user_role: “editor” }
          case CHANGE_USER_ROLE_TO_AUTHOR:
               return { user_role: “author” }

          default:
               return state
     }
}

Retrieving the State

The mapStateToProps function retrieves the state from the store and passes it as a prop to the component. Then, the object property can be instantiated in the component just like any other prop. With the component now connected to the store and fetching the state, the component will be re-rendered each time the state changes.

const mapStateToProps = state => {
     return {
          user_role: state.user_role
     }
}

Changing the State

You can use the mapDispatchToProps function to perform changes in the state. With the bindActionCreators method, you wrap each action in the dispatch method to be invoked directly and individually.

This way, you can now call the actions changeUserRoleToEditor and changeUserRoleToAuthor from an onclick event in a button element. When the user clicks the button, the actions are performed, the reducer is executed, and the state is changed. Once the state changes, all components connected to the store and listening to the state are re-rendered accordingly.

const mapDispatchToProps = dispatch => {
     return bindActionCreators({
          changeUserRoleToEditor,
          changeUserRoleToAuthor
     },
     dispatch
     )
     }
render() {
     const { changeUserRoleToEditor, changeUserRoleToAuthor } = this.props
     return(
          <div>
               <Button onClick={changeUserRoleToEditor}> Change User Role to Editor</Button>
               <Button onClick={changeUserRoleToAuthor}> Change User Role to Author</Button>
          </div>
     )
}
}

Returning to the Hooks example, you don’t need many of the steps required to create a state, store information on it, and then later change it to something new.

But that is pretty much for a small to medium-scale app. A project with just a few components in the hierarchy and not even half of the components required to access the state or change it would benefit from state management with Hooks. The state can be accessed and passed between components as props with this method.

When you have a project with multiple components in the hierarchy and a complex component structure, you may have a better benefit from implementing a third-party state management tool that provides a global store to hold the state in your app and connect the specific components that need to access the state.

Wrapping Up

State management is possible with React Hooks without a third-party tool such as Redux. In fact, it is a straightforward approach because you don’t need to deal with the installation of a third-party tool. Also, it can be said that you write less code by implementing state management with Hooks.

Ultimately, deciding between React Hooks vs Redux is a matter of preference. Regardless of your choice, Liquid Web has the hosting covered with VPS Hosting options perfect for beginning your next project. Contact our sales team to get started.

Avatar for Juan Machado

About the Author: Juan Machado

Juan José is an assiduous WordPress enthusiast, with a mission to become a better software engineer. He enjoys teaching and helping other people to dip their toes in software development.

Latest Articles

How to use kill commands in Linux

Read Article

Change cPanel password from WebHost Manager (WHM)

Read Article

Change cPanel password from WebHost Manager (WHM)

Read Article

Change cPanel password from WebHost Manager (WHM)

Read Article

Change the root password in WebHost Manager (WHM)

Read Article