Developer 1 and Developer 2 were fighting over which state management tool is better- Redux or Context API. They both listed pros and cons but sadly none realized the actual use case and purpose of Redux and Context API.

If you’re one of the developer 1 or 2, then continue reading the tutorial to learn why it shouldn’t be Redux vs Context API.

Introduction

If you’re having a Javascript background then you might be familiar with the terms Redux and Context API. And probably, you might have come across so many blogs that debate on which is better- Redux vs Context API. I assumed the same unless I realized it’s not!

After reading a bunch of blogs, I concluded the purpose of both the tools and how different they are from each other. If you aren’t aware yet, don’t worry this tutorial will help you understand the use cases of both tools with a basic demo example. Here, we will build an app using both approaches and discuss them.

Let’s get started, then!

Tutorial Goal

  • Understanding Redux and Context API
  • Comparing the working of Redux and Context API
  • Exploring the purpose and use case of Redux and Context API
  • A demo application using Redux and Context API approach

Redux: Introduction and Building Blocks

According to documentation-

Redux is a pattern and library for managing and updating application state, using events called “actions”. It serves as a centralized store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a predictable fashion.

The documentation clearly mentions that redux is for “managing state” and understanding how the state is updated.

Use Cases of Redux

  • The primary goal of redux, as mentioned in the doc, is to manage and keep track of the state.
  • Keeping your state management logic separate from the user interface layer
  • Faster logic debugging

Redux is mainly used to manage the state of React applications in a centralized place where to access the state anywhere in the application. Technically, The concept of Redux is based on Flux architecture and this concept isn’t restricted to React apps; there are implementations in different technologies, as well (e.g. NgRx for Angular). But Redux is particularly implemented with React.

Packages needed

  • redux: For the functions like createStore(), combineReducer() etc.
  • react-redux: For the functions like connect() etc.

Building Blocks of Redux

It consists of mainly four building blocks:

1. Reducer: These are functions with state and actions passed in as arguments. It contains “action.type” in switch cases which returns the changed value. It optionally accepts the payload (generally created in a separate file known as reducers.js)

2. Store: Store is the collection of all data. You can pass it to the provider.

3. Provider: A React component that accepts store as an argument (usually created in index.js)

4. Actions: Functions that provide/return action type and payload to the dispatcher which will further call the respective reducer (generally created in a separate file known as actions.js)

Building Blocks of Redux

Context API: Introduction and Building Blocks

React documentation explains context API as-
Context provides a way to pass data through the component tree without having to pass props down manually at every level.

In a typical React application, data is passed top-down (parent to child) via props, but such usage can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.

If you can observe the documentation states context for “passing” and “sharing” values and mention nothing about “managing the state”

Use Cases of Context API

The main purpose of using context API is avoiding ‘prop drilling’ – passing prop at every level. It is more like a pipeline used to pass values from one end to another.

Context API provides the easiest way for passing data through the component tree so that you don’t have to pass props down manually at every level. For example, assume we have a component tree consisting of A, B, C, and D components. Now you need to pass props from A to D, so rather than passing it A > B > C > D,i.e., to every component, with the help of context you can directly pass to A > D.

Now, many blogs have mentioned that Context API is the best replacement for Redux because it’s in-built and you don’t have to install dependencies for the same. Is this really true- Can Context API replace Redux? We will discuss this in a further section. Stay tuned to explore!

Building Blocks of Context API

We can divide the Context API into three blocks:
1. Context: Use createContext() function that takes the default value as a first argument. Here it is optional to pass a Javascript object. You can implement multiple contexts in your app.

2. Provider: After creating context, the Provider provides the capability for accessing the context. It provides functions & data to pass values further to the component.

3. Consumer: Consumer allows access to the value to child components which are wrapped by Provider. It has two types-

  • Context.Consumer: Context.Consumer can be used for both functional and class-based components. However, through this approach, the context is accessible within the render method only.
  • Static ContextType: Static contextType can be used only for Class-based components.

Redux and Context API Example

  • The example below is based on a Counter. The initial value will be 0 and it has two buttons to increment and decrement the value.
  • Inside the main parent counter component, there will be three child components-

• one for changing the counter value
• two for each of the buttons.

The initial setup would be the same for both Context and Redux approaches.

Are you struggling to choose between the Context and Redux approach and implement it in your application?
Get in touch with our tech experts or sure-handed developers to choose what’s best for your project requirements. Hire React Native developer to make the implementation hustle-free and painless!

Create a React Native App

Initially, create a react native app using the following command

Copy Text
react-native init CounterDemo

Redux Approach: How to Implement Redux in React Native App?

Install Required dependencies for Redux

Copy Text
npm install redux --save
npm install react-redux --save
The Redux Approach

Redux Store Set Up

We will create our store within our App.js file.

// App.js

Copy Text
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import totalReducers from './reducers/index.js';
import Counter from './components/counters';
 
const store = createStore(totalReducers);
 
export default class App extends Component{
  render(){
    return(
      
        
      
    );
  }
}
  • Here we are importing totalReducers from the reducers folder.
  • createStore() function accepts one argument as totalReducers object and generates the store.
  • The Provider component makes sure the store is available throughout the application.

Reducers Set Up

Reducers return the data required by the application. In this demo, the reducer will return the updated counter value. Here is our counterReducer.js file inside the reducers folder.

// reducers/counterReducer.js

Copy Text
let count= 0;
 
export default (state = count , action) => {
    switch (action.type) {
        case "Increment": 
            count ++
            break;
        case "Decrement": 
            count --
            break;
        default:
            count;
    }
    return count;  
}

Explanation

  • The reducer defined above will always return the count value.
  • Increment & Decrement are the actions types that will update the value as shown above.
  • We will combine all the reducers inside the index.js file inside the reducers folder.

// reducers/index.js

Copy Text
import {combineReducers} from 'redux';
import counterReducer from './counterReducer';
 
const totalReducers= combineReducers({
  count: counterReducer,
});
 
export default totalReducers;

Explanation

  • Here we will combine all the reducers as arguments of the combineReducers() function of the Redux library.

Actions Set Up

Create two actions: Increment & Decrement.

// actions/index.js

Copy Text
export function increment(){
    return{
      type: "Increment"
    };
  }
 
export function decrement(){
  return{
    type: "Decrement"
  };
}

UI Component

We will simply create only one component called a counter component. For using reducers and actions, we have to implement these functions:

  • mapStateToProps() – It simply accepts your reducer data, and converts it into a simple usable prop. With the help of this.props.data we will use data as a prop in our component.
Copy Text
function mapStateToProps(state){
    return{
      count: state.count
    };
}

Note: Keep in mind how we assigned names to reducers in the combineReducers function because we have to use the same name for calling respective reducers.

  • mapDispatchToProps() – It accepts your actions, and converts them into a simple usable prop.
Copy Text
function mapDispatchToProps(dispatch){
        return bindActionCreators({increment, decrement}, dispatch)
}

Note: bindActionCreators function simply combines our actions into one object.

Moving towards the component that manages the user interface.

// component/counter.js

Copy Text
class Counters extends Component {
  constructor(props) {
    super(props);
  }
 
  render() {
    return (
      
        
          {'The Redux Approach'}
        
        {this.props.count}
        
           this.props.increment()}>
            Increment +
          
           this.props.decrement()}>
            Decrement -
          
        
      
    );
  }
}
 
function mapStateToProps(state) {
  return {
    count: state.count,
  };
}
 
function mapDispatchToProps(dispatch) {
  return bindActionCreators({increment, decrement}, dispatch);
}
 
export default connect(mapStateToProps, mapDispatchToProps)(Counters);

For styling your component you can use the below code

Copy Text
const styles = StyleSheet.create({
  mainContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  counterNumber: {
    fontSize: 35,
    fontWeight: 'bold',
  },
  buttonContainer: {
    flexDirection: 'row',
  },
  buttonStyle: {
    backgroundColor: 'green',
    borderWidth: 1,
    height: 30,
    width: '25%',
    borderRadius: 5,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

Finishing up

So far we are done with redux set up, logic, and user interface for the counter demo. Now, just a simple step remaining – import our App file in our index.js file.

// index.js

Copy Text
import {AppRegistry} from 'react-native';
import App from './src/App.js';
import {name as appName} from './app.json';
 
AppRegistry.registerComponent(appName, () => App);

Git Repo link: https://github.com/sunil-bacancy/CounterDemo

Context API Approach: How to Implement Context API in React Native App?

Since the context API is in-built functionality we don’t need to install third-party dependencies.

The Context API approach

Folder structure

Create a folder src at the root of your app. Within the src folder, we have to create 3 folders that are reducers, components, state and one file App.js.

Reducer Set Up

Just like Redux, declare reducer with Context API.

// reducers/globalReducer.js

Copy Text
export default countReducer = (state , action) => {
    switch (action.type) {
        case "Increment": 
            return{
                ...state,
                counter: state.counter + 1,
            }
        case "Decrement": 
            return{
                ...state,
                counter: state.counter - 1,
            }
        default:
            return{
                state
            }
    }  
}

Create the context

  • Create a context using createContext() and pass the initial state as arguments. You can also define without passing arguments.
  • Define a function that will pass the data via Provider.
  • useReducer() will take a reducer having default state, then return the updated value and dispatch the function.
  • Inside the Provider function, use useReducer() with arguments- reducer and initial state. The returned and dispatched states are later passed as values to the Provider.

// state/globalState.js

Copy Text
import React, {createContext, useReducer} from 'react';
import countReducer from '../reducers/globalReducer';
 
const initialState = {
    counter: 0
}
 
export const GlobalContext = createContext(initialState);
 
export default GlobalProvider = ({children}) => {
    const [state, dispatch] = useReducer(countReducer, initialState);
 
    return(
        
            {children}
        
    )
}

Providing Context

After creating the context, we need to provide the context so that it is accessible in the child components. For that, you need to wrap it within the Provider.

// src/App.js

Copy Text
import React, { Component } from 'react';
import GlobalProvider from './state/globalState';
import Counters from './components/counter';
 
export default class App extends Component {
    render(){
        return (
            
                
            
        )
    }
}

Consuming Context

Use useContext() for consuming the context in respective child components.

// components/counter.js

Copy Text
import React, { Component, useContext } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import {GlobalContext} from '../state/globalState';
 
const Counters = () => {
 
   const {state} = useContext(GlobalContext);
   const {dispatch} = useContext(GlobalContext);
 
   return(
      
          
            {'The Context API Approach' }
              
                 { state.counter  }
              
                
                   dispatch({type: "Increment"})}
                   >
                     
                       Increment +
                     
                   
                    dispatch({type: "Decrement"})}
                   >
                     
                       Decrement -
                     
                   
             
       
    )
}
 
export default Counters;

For styling your component you can use the below code.

Copy Text
const styles = StyleSheet.create({
    mainContainer: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center'
    },
    counterNumber: {
        fontSize: 35,
        fontWeight: 'bold'
    },
    buttonContainer: {
        flexDirection: 'row'
    },
    buttonStyle: {
        backgroundColor: 'green',
        borderWidth: 1,
        height: 30,
        width: '25%',
        borderRadius: 5,
        justifyContent: 'center',
        alignItems: 'center', 
    },
})

Git Repo link: https://github.com/sunil-bacancy/CounterContextDemo

Redux and Context API: Comparison

Redux

  • Storing and managing values
  • Works outside React components
  • Avoids prop-drilling
  • Through dispatching an action one can update the value
  • Provides DevTools to show history of actions and state values
  • Allows application code for triggering side effects through middlewares

Context API

  • Not for storing or managing values
  • Works in React components only
  • Passes a single value be it objects, primitives, classes, etc.
  • Avoids prop-drilling
  • Provides current context value for Provider and Consumer but doesn’t display any history of how the value is changed.
  • Excludes side effects mechanism – exclusively for component rendering

Conclusion

I hope the tutorial helped you understand how different Context and Redux are. Moreover, try to implement both the approaches and play around with the code to dig deeper. For more such React Native tutorials, we have a React Native Tutorials page that consists of step-by-step guidelines with the github source.

I can understand how difficult it can be to organize and manage a global store for a complex application, and also how precise you need to be for implementing Context API in your application. In case you have a large and complex project and want to implement Redux or Context API then feel free to contact us and hire React Native developer.

Hire React Native Developer

Connect Now

Get In Touch

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?