DEV Community

zahidkhan-xen
zahidkhan-xen

Posted on • Updated on

Context API vs. Redux: When and Why to Use Them in React

Before starting to explore the differences and use cases of both Context API and Redux, it is essential to understand why these two solutions were developed.

In simple React, we can pass down data from parent components to child components. The parent component is where your main component is rendering. For example:

Let's say we have a component named Greet.js, and this component is rendering in App.js, making App.js its parent component. If we pass a constant firstName with the value "John", it will look like this:

//App.js
export const App = () => {
  const firstName = "John";

  return (
    <Greet name={firstName} />
    <Profile name={firstName} />

  );
}
Enter fullscreen mode Exit fullscreen mode
// Greet.js
export const Welcome = ({ name }) => {
  return <h1>Welcome : {name}</h1>;
}
Enter fullscreen mode Exit fullscreen mode
//Profile.js
export const Profile = ({ name } => {
return <h1> userName : {name} </h1>
Enter fullscreen mode Exit fullscreen mode

This above method also known as Prop Drilling .Passing props can become inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop the prop drilling becomes complex and then for passing props we use context API.

Context API:

Context is a way to pass data through the component tree without having to pass it down manually at every level.It's beneficial for sharing data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.
There are three step to implement Context API:

Create a Context: Define a context to hold the state.

Provide Context: Wrap the top-level component with the context provider.

Consume Context: Use the context in the child components to access the state.

1-Create a Context

// UserContext.js
import React, { createContext, useState } from 'react';

const UserContext = createContext();

const UserProvider = ({ children }) => {
  const [name, setName] = useState("John");

  return (
    <UserContext.Provider value={{ name }}>
      {children}
    </UserContext.Provider>
  );
};

export { UserContext, UserProvider };
Enter fullscreen mode Exit fullscreen mode

2-Provide Context

// App.js

import React from 'react';
import { UserProvider } from './UserContext';
import Welcome from './Welcome';
import Profile from './Profile';

const App = () => {
  return (
    <UserProvider>
      <div>
        <Welcome />
        <Profile />
      </div>
    </UserProvider>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

3-Consume Context

// Welcome.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';

const Welcome = () => {
  const { name } = useContext(UserContext);

  return <h1>Welcome: {name}</h1>;
};

export default Welcome;
Enter fullscreen mode Exit fullscreen mode
// Profile.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';

const Profile = () => {
  const { name } = useContext(UserContext);

  return <h1>userName: {name}</h1>;
};

export default Profile;
Enter fullscreen mode Exit fullscreen mode

Using the Context API allows data to flow anywhere in the component tree, making it a superior method for managing application state compared to prop drilling. However, as applications grow in complexity and certain side effects become challenging to manage within individual components, Redux emerges as a powerful solution.

React Redux

Redux simplifies state management by centralizing it through a global store. It not only eliminates the need for prop drilling but also provides an efficient way to handle side effects using middleware. This approach ensures that side effects, such as asynchronous data fetching or logging, are managed centrally, keeping components focused solely on UI rendering.

Let's understand it with example :
These steps involved in Redux data flow:

Create Action : Define action to be perform

Create Reducer : Define how to perform action and update it

Create Store : Recieved updated state from Reducer and make it available to call in any component.

1.Create Action

// userActions.js
export const setName = (name) => ({
  type: 'SET_NAME',
  payload: name,
});

Enter fullscreen mode Exit fullscreen mode

2.Create Reducer

// userReducer.js
const initialState = {
  name: 'John', // initial state
};

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_NAME':
      return { ...state, name: action.payload };
    default:
      return state;
  }
};

export default userReducer;
Enter fullscreen mode Exit fullscreen mode

*3.Create Store *

// store.js
import { createStore } from 'redux';
import userReducer from './userReducer';

const store = createStore(userReducer);

export default store;

Enter fullscreen mode Exit fullscreen mode

Wrap your application with the Redux Provider component to make the store available to all components.

// App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Welcome from './Welcome';
import Profile from './Profile';

const App = () => {
  return (
    <Provider store={store}>
      <div>
        <Welcome />
        <Profile />
      </div>
    </Provider>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Now, you can use this globally in any component by using useSelector hook :

// Welcome.js
import React from 'react';
import { useSelector } from 'react-redux';

const Welcome = () => {
  const name = useSelector(state => state.name);

  return <h1>Welcome: {name}</h1>;
};

export default Welcome;
Enter fullscreen mode Exit fullscreen mode

Conclusion:

In the end, whether you choose React's Context API or Redux depends on what your application specifically requires and the particular challenges it faces.

Top comments (0)