DEV Community

Cover image for  React State Management: When to use the Context API over Redux
Alexei Dulub
Alexei Dulub

Posted on • Edited on

React State Management: When to use the Context API over Redux

React State Management: When to use the Context API over Redux

React is a library that was primarily created to build interactive and highly appealing frontends. It utilizes a component-based architecture to allow maximum code reusability and a bunch of other things. State is something that developers in any field have to grapple with at some point in time, in React too there were a lot of challenges that developers faced, much of which Redux a state management library solved. Overtime React evolved to try and solve some of these problems by itself, the Context API is the result of this attempt. This article will discuss both Redux and the Context API and identify some guidelines that can help you choose one over the other.

Prerequisites

This post is aimed at developers that have a good amount of experience with writing web applications in Javascript and ReactJS. If you are familiar with another frontend framework/library like VueJS, AngularJS, SvelteJS, etc. you can still make use of this article.

✅ Experience with writing web apps using ReactJS
✅ Some experience with Redux and preferably the Context API

⭐ Make sure to check the resources topic to learn more!

Outcomes

By reading this post will be able to:

  • Understand that sometimes you do not need either Redux or Context.
  • Know what exactly the Context API provides which can help you make decisions.
  • Understand when you could use the Context API for state management over Redux.

State Management: The challenges

State management is not easy, despite the kind of application you're writing as long as it will face production at some point or have a couple of complex features. While in the initial phases of creating an application, a lot of thought goes into making the "best" decisions and this is commonly associated with what a lot of people in any community call the "best" tools. Redux is one of those "best" tools, that have been used since 2015 but does this mean that you should rely on Redux to solve any possible future problems? No.

Just like how when you have a hammer, every problem shouldn't be a nail for you, wherever state management has to be done you shouldn't sprinkle Redux. This can lead to inefficiency, which in turn leads to time being wasted.

With that bit understood, you should know about a few challenges that a lot of people use Redux to solve but really shouldn't:

  • Sharing state that could have instead be passed down as props.
  • Managing the state of a form - There is no need to do so, as the state of a form does not affect the application as a whole. Libraries like Formik help to do this better.
  • Using it in any situation that complicates how you tackle it instead of making it easier.

Context API: A solution for when Redux is too much

The context API is nothing new, it has been around for a while but was officially announced in React version 16.3. The purpose you could say for introducing the Context API is to make passing data through deeply nested components simple. It is not a solution for state management, and all the logic that is required to manage your state must be written by yourself. You could better word this by saying that the Context API does not manage your state for you.

This makes it very flexible, you can adapt it to your needs and pass state through nested trees of components easily. Let's implement a simple UI where a Navigation Bar holds a User Avatar. It would look a little like this:

const UserContext = React.createContext()

const ProfilePicture = () => (
    <UserContext.Consumer>
        {(user) => <img width="56px" alt="pfp" src={user.pfp} />}
    </UserContext.Consumer>
)

const Nav = () => (
    <nav>
        <ProfilePicture />
    </nav>
)

class App extends React.Component {
    state = {
        user: {
            pfp: 'https://i.picsum.photos/id/50/200/300.jpg',
        },
    }

    render() {
        return (
            <div className="app">
                <UserContext.Provider value={this.state.user}>
                    <Nav />
                </UserContext.Provider>
            </div>
        )
    }
}

First off, you need to create a context, the context mainly holds 2 properties Provider and Consumer, both exist for a self-explanatory purpose. The provider must be used to wrap the major portion of the application that will consume the value that it provides, while the consumer simply consumes the value and passes it off to the component that requires it. This way passing data in nested subtrees of components can be greatly simplified.

Redux: A solution for advanced state management

Redux is a state management library that mixed quite a few different concepts from libraries like Flux and languages like Elm, to make state management as painless and testable as possible. It achieves this by living up to three fundamental principles:

  1. Singe source of truth - Having a single store makes it easy to debug and test your application, features that are otherwise difficult implement are made extremely simple because you know that all your state is in one single store, hence the only source of truth in your application.
  2. State should be read-only - You should only ever show intent to modify the state, this prevents your UIs or network calls from modifying the state directly. This intent is displayed using plain objects that are called actions. This makes it easier to debug and test the application.
  3. Changes must be made using pure functions - The actual modification must be done using pure functions called reducers. Pure functions take an input and return the same output for that particular input and there are no side effects. Reducers simply take the current state and return the next state.

To get a better grasp of using Redux, let's implement the same example from before but use Redux instead of Context:

import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { connect, Provider } from 'react-redux'

const initialState = {}

function reducer(state = initialState, action) {
    switch (action.type) {
        case 'SET_USER':
            return {
                ...state,
                user: action.user,
            }
        default:
            return state
    }
}

const store = createStore(reducer)

store.dispatch({
    type: 'SET_USER',
    user: {
        pfp: 'https://i.picsum.photos/id/50/200/300.jpg',
    },
})

const mapStateToProps = (state) => ({
    user: state.user,
})

const UserAvatar = connect(mapStateToProps)(({ user }) => (
    <img width="56px" alt="pfp" src={user.pfp} />
))

const Nav = () => (
    <nav>
        <UserAvatar />
    </nav>
)

const App = () => (
    <div className="app">
        <Nav />
    </div>
)

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.querySelector('#root')
)

If you have never used Redux before, the above code example might be a little daunting but fear not there is no magic involved. Redux uses Context behind the scenes to make state available to a lot of different components. Quite often, developers take this point to say that the Context API will eventually replace Redux, but that is not and never will be the case. Redux is not just a simple wrapper around Context, before we get to that however let's discuss how Redux works in the example above.

First off, you must create a store using createStore(), this function will take the reducer that will be used in your application to modify the state stored in your store. The reducer() is a pure function that contains the logic as to how the state should be modified based on the actions ( The { type: ...} object is an action) dispatched to the store. connect() is a pure function that makes all the associated components pure so that they will only rerender when the relevant part of the store updates.

Redux vs Context API: Which should you use?

If you read the previous two topics thoroughly, now it should be very apparent to you when you should use Context over Redux. However for those that still find it difficult to make the decision, it is worth taking note of the following points.

If you use Redux, then you can make use of:

  • The Redux DevTools extension - This tool makes it very easy to inspect your store, and debug it by performing actions like diffing and tracing. You could even replay the actions you have dispatch. If you feel like debugging will be a tough candy to crack, then this extension is worth a shot. It can be installed as a package or downloaded from an extension store and configured in your codebase.
  • Middleware - Middleware is simply functions that execute every time that an action has been dispatched. Redux Thunk for example, is a very popular middleware that makes dispatching actions asynchronously possible or Redux Observable that makes use of RxJS to make side effects.
  • Testability - Using Redux will make testing easier when it comes to complex applications because of the way it has been built.

Lastly, it is important to address the fact that Redux is not something that is dead or will be deprecated anytime soon, even in the React ecosystem. Regardless, even if people stop using it in the React ecosystem, it will still be used outside of React. React Native, for example, is a framework for building mobile applications, and uses redux for state management, while it could be said that React Native is part of the React ecosystem, this is a fine example of how Redux will still prevail even outside of React itself.

Some alternatives to Redux that are worth mentioning:

  • MobX - A relatively new library that solves a lot of the problems that Redux does.
  • GraphQL - A solution for data-driven applications, it makes this possible by making it so that the frontend need not know exactly how to fetch data to get the right response.

A little about PixelPlex

PixelPlex is a software development company that has been delivering outstanding blockchain, web, game and so many more development services since 2007. With over 300+ products delivered, it's safe to say that your project is safe in our hands. If you wish to turn your dream SaaS into a beautiful reality, or start working on that one idea that you always wanted to, visit our software development company website and get in touch!

Summary

✅ ReactJS is a frontend library for building beautiful UIs, state management is challenging and can be performed using a library like Redux.
✅ The Context API was introduced to React in version 16.3 and is ideal for when you need to pass data through deeply nested component trees, however, it does not manage your state for you, and you must write that logic on your own.
✅ Redux is a state management library fit for situations where testability and maintainability are prime factors. Redux provides the usage of middlewares that can expand the potential of redux.
✅ The Context API is not a replacement to Redux, it never will be either. Whether or not you use Context over Redux, depends on your particular situation.

Resources

Feel like reading more? Check these links out:

  • Redux vs React’s Context API - An article by Academind that makes use of a few more code examples to bring out the differences between Redux and Context.
  • Awesome Redux - A whole bunch of resources regarding Redux, if you want to start learning Redux, then you should check this out.
  • Formik - While this isn't a resource you should read about to understand Redux or Context better, it is a library worth checking out if you struggle with state management in forms.

Top comments (3)

Collapse
 
oscarromero profile image
Oscar Romero

Great post, Now I have a clear concept of both.

Collapse
 
thisdotmedia_staff profile image
This Dot Media

Love this article! Really great format and well-explained😊

Collapse
 
ajaypatel profile image
FoodBite

Easy peasy is also worth mentioning... :)
Also what kind of state management we can use if we are using graphql in backend